✔ 랜덤 포레스트 - 의사결정나무는 매우 훌륭한 모델이지만, 학습데이터에 오버피팅하는 경향이 있다. - 가지치기 같은 방법을 통해 부작용을 최소화 할 수 있지만, 한계가 있다. - 학습을 통해 구성해 놓은 다수의 나무들로부터 분류 결과를 취합해서 결론을 얻는 방식의 모델 랜덤포레스트는 !
cf) 앙상블 모델 여러개의 머신러닝 모델을 이용해서 최적의 답을 찾아내는 기법
데이터로 실습
목표: 어떤 컬럼이 예약 취소율과 관련이 있을 지
1.기초설정
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
hotel_df = pd.read_csv ( '/content/drive/MyDrive/KDT-1/머신러닝과 딥러닝/hotel.csv' )
✔컬럼 설명 * hotel : 호텔 종류 * is_canceled : 취소 여부 * lead_time : 예약 시점으로 부터 체크인이 될때 까지 기간(얼마나 미리 예약 했는지) * arrival_date_year: 예약 연도 * arrival_date_month : 예약 월 * arrival_date_week_number : 예약 주 * arrival_date_day_of_month : 예약 일 * stays_in_weekend_nights : 주말 포함 숙박일 * stays_in_week_nights : 평일 포함 숙박일 * adults : 성인 인원* children : 어린이 인원 * babies : 아기 인원 * meal : 식사 형태 * country : 지역 * distribution_channel : 유입 경로 * is_repeated_guest : 재방문 고객 여부 * previous_cancellations : 이전 예약 취소 여부 * previous_bookings_not_canceled : 예약을 취소하지 않고 정상 숙박한 횟수 * reserved_room_type : 예약 객실 타입 * assigned_room_type : 실제 배정된 객실 타입 * booking_changes: 예약 후 서비스가 몇번 변경되었는지 * deposit_type: 요금 납부 방식 * days_in_waiting_list: 예약을 위해 기다린 날짜 * customer_type: 고객 타입 * adr : 특정일에 높아지거나 낮아지는 가격 * required_car_parking_spaces : 주차공간 필요 여부 * total_of_special_requests : 별도의 요청 사항 * reservation_status_date: 예약한 날짜 * name : 이름 * email : 이메일 * phone-number : 핸드폰 번호 * credit_card : 신용카드 번호
2. 필요없는 컬럼 제거하기
개인정보 제거하기
hotel_df.drop ([ 'credit_card' , 'phone-number' , 'email' , 'name' , 'reservation_status_date' ], axis= 1 , inplace= True )
3.관련있어보이는 컬럼 찾기 (이상치 확인)
후보1) lead_time : 예약 시점으로 부터 체크인이 될때 까지 기간(얼마나 미리 예약 했는지)
sns.displot ( hotel_df [ 'lead_time' ])
sns.boxplot ( hotel_df [ 'lead_time' ])
후보2 ) distribution_channel : 유입 경로
sns.barplot ( x=hotel_df [ 'distribution_channel' ], y=hotel_df [ 'is_canceled' ])
오차율이 높은 관계로 한번 개수 확인
hotel_df [ 'distribution_channel' ] .value_counts ()
후보3) hotel : 호텔 종류
sns.barplot ( x=hotel_df [ 'hotel' ], y=hotel_df [ 'is_canceled' ])
후보4) arrival_date_year: 예약 연도
sns.barplot ( x=hotel_df [ 'arrival_date_year' ], y=hotel_df [ 'is_canceled' ])
후보5) arrival_date_month : 예약 월
plt.figure ( figsize= ( 15 , 5 ))
sns.barplot ( x=hotel_df [ 'arrival_date_month' ], y=hotel_df [ 'is_canceled' ])
1월부터 정리가 되지 않았음
✔ 1월부터 나오게 정렬하기
# 월 별로 정렬하기
plt.figure ( figsize= ( 15 , 5 ))
sns.barplot ( x=hotel_df [ 'arrival_date_month' ], y=hotel_df [ 'is_canceled' ], order=month )
후보6) is_repeated_guest : 재방문 고객 여부
sns.barplot ( x=hotel_df [ 'is_repeated_guest' ], y=hotel_df [ 'is_canceled' ])
후보7) deposit_type: 요금 납부 방식
sns.barplot ( x=hotel_df [ 'deposit_type' ], y=hotel_df [ 'is_canceled' ])
오차율이 높은 관계로 한번 개수 확인
hotel_df [ 'deposit_type' ] .value_counts ()
plt.figure ( figsize= ( 20 , 30 ))
sns.heatmap ( hotel_df.corr (), cmap= 'coolwarm' , vmax= 1 , vmin= -1 , annot= True )
#vmax, vmin= -1 ~ 1 사이로 정렬 해달라
#annot=True : 박스안에 해당 숫자를 넣는 것
파생변수 설정
1. 사람인원수
2. 총 숙박일
hotel_df [ 'people' ] = hotel_df [ 'adults' ] + hotel_df [ 'children' ] + hotel_df [ 'babies' ]
hotel_df [ 'total_nights' ] = hotel_df [ 'stays_in_weekend_nights' ] + hotel_df [ 'stays_in_week_nights' ]
arrival_date_month의 value 값을 개월로 바꾸기
hotel_df [ 'arrival_date_month' ] .apply ( lambda x : 'spring' if x in [ 'March' , 'April' , 'May' ] else 'summer' if x in [ 'June' , 'July' , 'Augest' ] else 'fall' if x in [ 'September' , 'Octorber' , 'November' ] else 'winter' )
#방법 2
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
hotel_df [ 'season' ] = hotel_df [ 'arrival_date_month' ] . map ( new_season_dic )
expected_room_type을 0,1로 바꾸기(예약했던적이 있는지 없는지)
# 예약 객실과 실제 배정 객실이 같을 경우 true/false가 나오는데 astype으로 int화 시키면 0,1로 된다.
hotel_df [ 'expected_room_type' ] = ( hotel_df [ 'reserved_room_type' ] == hotel_df [ 'assigned_room_type' ]) .astype ( int )
취소율 구하기
hotel_df [ 'cancel_rate' ] = hotel_df [ 'previous_cancellations' ] / ( hotel_df [ 'previous_cancellations' ] + hotel_df [ 'previous_bookings_not_canceled' ])
hotel_df [ 'cancel_rate' ] .value_counts ()
#타입이 obj인 컬럼만 빼오기
obj_list = []
for i in hotel_df.columns :
if hotel_df [ i ] .dtype == 'O' :
obj_list.append ( i )
각 컬럼별 분류개수 보기
for i in obj_list :
print ( i , hotel_df [ i ] .nunique ())
학습데이터 검증데이터 나누기
독립변수: 나머지 컬럼들
종속변수: 취소율
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= 12345 )
모델 학습시키기 (분류의 배깅 모델 사용 예정)
from sklearn.ensemble import RandomForestClassifier
rf= RandomForestClassifier ()
rf.fit ( X_train , y_train )
pred1= rf.predict ( X_test )
# 예측 결과를 %로 보고싶을 때
proba1 = rf.predict_proba ( X_test )
proba1
0일확률 vs 1일 확률
테스트 데이터를 예측한 결과를 보고싶다.
# 첫번째 테스트 데이터에 대한 예측 결과
proba1 [ 0 ]
# 모든 테스트 데이터에 대한 취소 확률을 찍어보고싶다.
proba1 [:, 1 ]
결과검증 지표
✔ ROC Curve - 이진 분류 의 성능을 측정하는 도구 - 민감도, 특이도로 그려지는 곡선을 의미 ✔특이도(FPR False Positive Rate)
✔민감도(True Positive Rate)
✔AUC(Area Under the ROC Curve) ROC커브와 직선 사이의 면적을 의미
결과검증 적용
정확도 / 혼돈행렬 / T사이킷런 / ROC
from sklearn.metrics import accuracy_score , confusion_matrix , classification_report , roc_auc_score
accuracy_score ( y_test , pred1 )
# 약 86% 정답률
confusion_matrix ( y_test , pred1 )
print ( classification_report ( y_test , pred1 ))
하이퍼 파라미터 수정하고 정확도 올려보기 max_depth = 30 (30층까지 가지를 내린다.) random_state = 12345(데이터 고정)
rf2= RandomForestClassifier ( max_depth= 30 , random_state= 12345 )
rf2.fit ( X_train , y_train )
proba2 = rf2.predict_proba ( X_test )
roc_auc_score ( y_test , proba2 [:, 1 ])
🔴최적의 파라미터 찾기🔴
GridSearchCV
원하는 모든 하이퍼 파라미터를 적용하여 최적의 값을 찾아준다.
설정법
from sklearn.model_selection import GridSearchCV
# 객체를 생성
# 갯수를 맞춰줄 필요가 없다.
params = {
'max_depth' : [ None , 10 , 30 , 50 ],
'min_samples_split' : [ 2 , 3 , 5 , 7 , 10 ]
}
학습하기
rf3= RandomForestClassifier ( random_state= 12345 )
#cv = 5 5조각으로 쪼개서 검사
grid_df = GridSearchCV ( rf3 , params , cv= 5 )
grid_df.fit ( X_train , y_train )
cv = 총 데이터를 n 조각으로 쪼개서 검사한다.
#최적의 파라미터 확인하기
grid_df.best_params_
✔ 피쳐 중요도 (feature Importances) * Decision Tree에서 노드를 분기할 때 해당 피쳐가 클래스를 나누는데 얼마나 영향을 미쳤는지를 표기하는 척도
proba3 = rf3.predict_proba ( X_test )
proba3
roc_auc_score ( y_test , proba3 [:, 1 ])
rf3.feature_importances_
✔ feature_importances_ 결정트리에서 노드가 분기될때 얼마나 영향을 미쳤는지 표기하는 척도
데이터 프레임으로 영향력 확인하기
feat_imp = pd.DataFrame ({
'features' : X_train.columns ,
'importance' : rf3.feature_importances_
})
총 결과 깔끔히 보기
feat_imp = pd.DataFrame ({
'features' : X_train.columns,
'importance' : rf3.feature_importances_
})
top10 = feat_imp.sort_values ( 'importance' , ascending= False ) .head ( 10 )
top10
plt.figure ( figsize= ( 5 , 10 ))
sns.barplot ( x= 'importance' , y= 'features' , data=top10 )