Hotel Dataset
# 필요한 모듈
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
# hotel 데이터셋 데이터프레임으로 읽어오기
hotel_df = pd.read_csv("파일경로")
hotel_df

# 데이터프레임 정보확인
hotel_df.info()


# 사용하지 않을 column 제거하기
hotel_df.drop(["name", "email", "phone-number", "credit_card", "reservation_status_date"], axis=1, inplace=True)
hotel_df.head()

# 데이터프레임 통계정보 확인
hotel_df.describe()

# lead_time 막대그래프로 확인
sns.displot(hotel_df["lead_time"])

# 박스그래프로 확인
sns.boxplot(hotel_df["lead_time"])

# distribution_channel과 is_canceled의 관계를 막대그래프로 확인
sns.barplot(x=hotel_df["distribution_channel"], y=hotel_df["is_canceled"])

# distribution_channel의 값들 개수확인
hotel_df["distribution_channel"].value_counts()

# hotel과 is_canceled의 관계 막대그래프로 확인
sns.barplot(x=hotel_df["hotel"], y=hotel_df["is_canceled"])

# arrival_date_year과 is_canceled의 관계 막대그래프로 확인
ns.barplot(x=hotel_df["arrival_date_year"], y=hotel_df["is_canceled"])

# arrival_date_month과 is_canceled의 관계 막대그래프로 확인
# column의 값들이 많아서 그래프 사이즈를 키움
plt.figure(figsize=(15, 5))
sns.barplot(x=hotel_df["arrival_date_month"], y=hotel_df["is_canceled"])

# 위 그래프에서 month의 순서가 섞여있어 정리를 위해 calender를 사용
import calendar
# calender 사용법
print(calendar.month_name[1])
print(calendar.month_name[2])
print(calendar.month_name[3])
print(calendar.month_name[4])

# 1월부터 12월까지 months배열에 담아준다.
months = []
for i in range(1, 13):
months.append(calendar.month_name[i])
months

# 그리고 다시 적용시킨다.
# order은 이름과 일치하게 순서를 정렬
plt.figure(figsize=(15, 5))
sns.barplot(x=hotel_df["arrival_date_month"], y=hotel_df["is_canceled"], order=months)

# is_repeated_guest와 is_canceled의 관계 막대그래프로 확인
sns.barplot(x=hotel_df["is_repeated_guest"], y=hotel_df["is_canceled"])

# deposit_type와 is_canceled의 관계 막대그래프로 확인
sns.barplot(x=hotel_df["deposit_type"], y=hotel_df["is_canceled"])

# deposit_type의 값들 개수확인
hotel_df["deposit_type"].value_counts()

corr()
- 각 열 간의 상관 계수를 반환하는 함수이다.
- 상관계수 산정 방정식에는 피어슨 상관계수, 켄달-타우 상관계수, 스피어먼 상관계수를 사용한다.
# 기본 사용법
df.corr(method='pearson', min_periods=1)
method : {pearson / kendall / spearman} 적용할 상관계수 방식입니다.
min_periods : 유효한 결과를 얻기위한 최소 값의 수 입니다. (피어슨, 스피어먼만 사용가능)
# 하나하나 그래프로 나타내서 보기에는 좋지않다. 따라서 corr() 함수 사용
# corr(): 열들 간의 상관관계를 계산하는 함수. (피어슨 상관계수)
# -1 ~ 1 까지의 범위를 가지며 0에 가까울수록 두 변수의 상관관계가 없거나 매우 약함
# seaborn 내부 heatmap을 사용하면 보기 편함, vmax, vmin은 범위,
# cmap은 색표현, annot(annotation)은 각 칸에 입력한다는 것(값표출)
plt.figure(figsize=(15, 15))
sns.heatmap(hotel_df.corr(numeric_only=True), cmap='coolwarm', vmax=1, vmin=-1, annot=True)

corr() 함수를 사용하면 그래프로 일일이 확인하지 않아도 전체적으로 확인할 수 있다.
(다시 위로 가서 보기 귀찮으니 여기서 이어서 하겠음)
# 데이터프레임 null값 확인.
hotel_df.isna().mean()

# null 비율이 적어서 날려버림
hotel_df = hotel_df.dropna()

# adults의 값이 0인것들 확인
hotel_df[hotel_df["adults"] == 0]

# people 파생변수를 만들기
# people = adults + children + babies
# 호텔을 예약하는데 수가 0인것은 이상함.
hotel_df['people'] = hotel_df['adults'] + hotel_df['children'] + hotel_df['babies']
hotel_df.head()

# people의 값이 0인 것들 확인
hotel_df[hotel_df["people"] == 0]
# people의 값이 0인 것을 제외
hotel_df = hotel_df[hotel_df['people'] != 0]
hotel_df

# total_nights 파생변수 만들기
# total_nights = stays_in_week_nights + stays_in_weekend_nights
hotel_df['total_nights'] = hotel_df['stays_in_week_nights'] + hotel_df['stays_in_weekend_nights']
hotel_df.head()

# total_nights의 값이 0인 것들 확인
hotel_df[hotel_df['total_nights'] == 0]

# season 파생변수
# arrival_date_month 를 참조하여 아래와 같이 생성
# 12, 1, 2: winter
# 3, 4, 5: spring
# 6, 7, 8: summer
# 9, 10, 11 : fall
season_dic = {'spring':[3, 4, 5], 'summer':[6, 7, 8], 'fall':[9, 10, 11], 'winter':[12, 1, 2]}
new_season_dic = {}
for i in season_dic:
for j in season_dic[i]:
new_season_dic[calendar.month_name[j]] = i
new_season_dic

# 데이터프레임에 적용
hotel_df['season'] = hotel_df['arrival_date_month'].map(new_season_dic)
hotel_df.head()

# 데이터프레임 정보확인
hotel_df.info()

# expected_room_type 파생변수 만들기
# expected_room_type = reserved_room_type와 assigned_room_type이 같으면 1 다르면 0
hotel_df['expected_room_type'] = (hotel_df['reserved_room_type'] == hotel_df['assigned_room_type']).astype(int)
hotel_df.head()

# cancel_rate 파생변수 만들기 (취소비율)
# cancel_rate = previous_cancellations / (previous_cancellations + previous_bookings_not_canceled)
hotel_df['cancel_rate'] = hotel_df['previous_cancellations'] / (hotel_df['previous_cancellations'] + hotel_df['previous_bookings_not_canceled'])
hotel_df.head()

# cancel_rate의 null(결측값)값 확인
hotel_df[hotel_df['cancel_rate'].isna()]
# null(결측값)값 -1로 채우기
hotel_df['cancel_rate'] = hotel_df['cancel_rate'].fillna(-1)
# 데이터프레임 정보확인
hotel_df.info()

object타입이 너무 많음
# hotel의 타입 확인
hotel_df["hotel"].dtype

object가 "O"라고 나옴
# object인 column들 가져와 배열에 담기
obj_list = []
for i in hotel_df.columns:
if hotel_df[i].dtype == 'O':
obj_list.append(i)
obj_list

# object 타입의 column들의 고유 값들 개수 뽑기
for i in obj_list:
print(i, hotel_df[i].nunique())

# country와 arrival_date_month의 고유 값이 많아서 제외
hotel_df.drop(['country', 'arrival_date_month'], axis=1, inplace=True)
# 배열에서도 제거
obj_list.remove('country')
obj_list.remove('arrival_date_month')
# 원 핫 인코딩, 대상 column들은 배열에 담긴 columns
hotel_df = pd.get_dummies(hotel_df, columns=obj_list)
hotel_df.head()

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(hotel_df.drop('is_canceled', axis=1),
hotel_df['is_canceled'],
test_size=0.3,
random_state=2024)
X_train.shape, y_train.shape

X_test.shape, y_test.shape

앙상블(Ensemble) 모델
- 여러개의 머신러닝 모델을 이용해 최적의 답을 찾아내는 기법을 사용하는 모델이다.
- 보팅(Voting)
- 서로 다른 알고리즘 model을 조합해서 사용한다.
- 모델에 대해 투표로 결과를 도출한다.
- 베깅(Bagging)
- 같은 알고리즘 내에서 다른 sample 조합을 사용한다.
- 샘플 중복 생성을 통해 결과를 도출한다.
- 부스팅(Boosting)
- 약한 학습기들을 순차적으로 학습시켜 강력한 학습기를 만든다.
- 이전 오차를 보완해 가면서 가중치를 부여한다.
- 성능이 매우 우수하지만 잘못된 레이블이나 아웃라이어에 대해 필요 이상으로 민감하다.
- AdaBoost, Gradient Boosting, XGBoosting, LightGBM
- 스태킹(Stacking)
- 다양한 개별 모델들을 조합하여 새로운 모델을 생성한다.
- 다양한 모델들을 학습시켜 예측 결과를 얻은 다음 다양한 모델들의 예측 결과를 입력으로 새로운 메타 모델을 학습한다.
랜덤 포레스트(Random Forest)
- 머신러닝에서 많이 사용하는 앙상블 기법 중 하나이며, 결정 나무를 기반으로 한다.
- 학습을 통해 구성해 놓은 결정 나무로부터 분류 결과를 취합해서 결론을 얻는 방식이다.
- 성능은 꽤 우수한 편이나 오버피팅 하는 경향이 있다.
- 랜덤 포레스트의 트리는 온본 데이터에서 무작위로 선택된 샘플을 기반으로 학습한다.
- 각 트리가 서로 다른 데이터셋으로 학습되어 다양한 트리가 생성되며 모델의 다양성이 증가한다.
- 각각의 트리가 예측한 결과를 기반으로 다수결 또는 평균을 이용하여 최종 예측을 수행한다.
- 분류와 회귀 문제에 모두 사용될 수 있으며 특히 데이터가 많고 복잡한 경우에 매우 효과적인 모델이다.
# import
from sklearn.ensemble import RandomForestClassifier
# 객체 생성
rf = RandomForestClassifier(random_state=2024)
# 훈련
rf.fit(X_train, y_train)

# 예측
# 각 입력 샘플에 대한 예측된 클래스 레이블을 반환한다.
pred1 = rf.predict(X_test)
pred1

# 각 입력 샘플에 대해 클래스별 확률을 반환한다.
# 반환된 값은 각 클래스에 속할 확률을 나타낸다.
proba1 = rf.predict_proba(X_test)
proba1

# 첫번째 테스트 데이터에 대한 예측 결과
proba1[0]

# 모든 테스트 데이터에 대한 호텔 예약을 취소할 확률만 출력
proba1[:, 1]

머신러닝/딥러닝에서 모델의 성능을 평가하는 데 사용하는 측정값
- Accuarcy : 올바른 예측의 비율
- Precision : 모델에서 수행한 총 긍정 예측 수에 대한 참 긍정 예측의 비율
- Recall : 실제 긍정 사례의 총 수에 대한 참 긍정 예측의 비율
- f1 score : 정밀도와 재현율의 조화 평균, 정밀도와 재현율 간의 균형을 맞추기 위한 단일 매트릭으로 사용
- AUC-ROC Curve : 참양성률과 가양성률 간의 균형을 측정
AUC : ROC 커브와 직선 사이의 면적을 의미. 범위는 0.5 ~ 1이며 값이 클수록 예측의 정확도가 높음
ROC Curve : 이진 분류의 성능을 측정하는 도구. 민감도와 특이도 사이의 관계
참고 : https://bioinformaticsandme.tistory.com/328
AUC-ROC 커브
AUC-ROC 커브 StartBioinformaticsAndMe 1. AUC - ROC Curve?: AUC-ROC 곡선은 다양한 임계값에서 모델의 분류 성능에 대한 측정 그래프임*ROC(Receiver Operating Characteristic) = 모든 임계값에서 분류 모델의 성능을 보여
bioinformaticsandme.tistory.com
# import
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report, roc_auc_score
accuracy_score(y_test, pred1)

confusion_matrix(y_test, pred1)

print(classification_report(y_test, pred1))

roc_auc_score(y_test, proba1[:, 1])

# 하이퍼 파라미터 수정(max_depth=30을 적용)
rf2 = RandomForestClassifier(max_depth=30, random_state=2024)
rf2.fit(X_train, y_train)
proba2 = rf2.predict_proba(X_test)
roc_auc_score(y_test, proba2[:, 1])

# 하이퍼 파라미터 수정 후
0.9319781899069026 -0.9315576511541386

import matplotlib.pyplot as plt
from sklearn.metrics._plot.roc_curve import roc_curve
fpr, tpr, thr = roc_curve(y_test, proba2[:, 1])
print(fpr, tpr, thr)

# 그래프로 확인
plt.plot(fpr, tpr, label="ROC Curve")
plt.plot([0, 1], [0, 1])
plt.show()

# 하이퍼 파라미터 추가 수정
# max_depth=30을 적용
# min_samples_split=5을 적용
# n_estimators=70을 적용
rf3 = RandomForestClassifier(min_samples_split=5, random_state=2024,
max_depth=30, n_estimators=70)
rf3.fit(X_train, y_train)
proba3 = rf2.predict_proba(X_test)
roc_auc_score(y_test, proba3[:, 1])

하이퍼 파라미터 최적의 값 찾기
- GridSearchCV : 원하는 모든 하이퍼 파라미터를 적용하여 최적의 값을 찾는다.
- RandomizedSearchCV : 원하는 하이퍼 파라미터를 지정하고 random 하게 조합하여 값을 찾는다.
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV
params = {
"max_depth": [30, 40, 50],
"min_samples_split": [3, 5, 7],
"n_estimators": [70, 120, 150]
}
# 객체 생성
rf4 = RandomForestClassifier(random_state=2024)
# CV : 데이터 교차 검증
grid_df = GridSearchCV(rf4, params) # cv: 데이터 교차검증
# 훈련
grid_df.fit(X_train, y_train)

# 가장 성능이 좋은 구간? 최고의 하이퍼파라미터(params) 조건을 보여줌
grid_df.best_params_

# 어떤 조합으로 학습을 시켰고, 어떤 파라미터들이 조합됐는지 알 수 있음
grid_df.cv_results_

# 비교하기
#객체 생성
rf5 = RandomForestClassifier(random_state=2024)
#객체 생성
rand_df = RandomizedSearchCV(rf5, params, n_iter=4, random_state=2024)
# 훈련
rand_df.fit(X_train, y_train)

rand_df.best_params_

rand_df.cv_results_

피처 중요도(Feature Importance)
- 결정 나무에서 노드를 분기할 때 해당 피처가 클래스를 나누는데 얼마나 영향을 미쳤는지 표기하는 척도이다.
- 0에 가까우면 클래스를 구분하는데 해당 피처의 영향이 거의 없다는 것이며, 1에 가까우면 해당 피처가 클래스를 나누는데 영향을 많이 줬다는 의미이다.
# 객체 생성
rf6 = RandomForestClassifier(random_state=2024, max_depth=40, min_samples_split=3, n_estimators=150)
# 훈련
rf6.fit(X_train, y_train)
# 예측
proba6 = rf6.predict_proba(X_test)
roc_auc_score(y_test, proba6[:, 1])

proba6

rf6.feature_importances_

# 결과를 가지고 데이터프레임으로 만들기(보기 쉽게)
feature_imp = pd.DataFrame({
"features": X_train.columns,
"importances": rf6.feature_importances_
})
feature_imp

# importances의 값을 기준으로 내림차순 정렬 객체
top10 = feature_imp.sort_values("importances", ascending=False).head()
plt.figure(figsize=(5, 10))
sns.barplot(x="importances", y="features", data=top10, palette="Set2")

'Python > 머신러닝, 딥러닝' 카테고리의 다른 글
Python 머신러닝 다양한 모델 적용하기 (0) | 2024.06.17 |
---|---|
Python 머신러닝 LightGBM (0) | 2024.06.16 |
Python 머신러닝 서포트 벡터 머신 (0) | 2024.06.12 |
Python 머신러닝 로지스틱 회귀 (0) | 2024.06.12 |
Python 머신러닝 의사 결정 나무 (1) | 2024.06.11 |