AI/머신러닝 - 예제

[머신러닝 - 예제] Hotel 데이터셋 - 랜덤 포레스트

caramel-bottle 2023. 12. 29.

1. Hotel 데이터셋

주제: 이 손님은 예약을 취소할까?

 

이번 데이터셋의 출처는 kaggle이다.

 

hotel.csv.zip
4.21MB

 


1-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/머신러닝과 딥러닝/data/hotel.csv')

 

 

# 요약 정보
hotel_df.info()

output>>

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 119390 entries, 0 to 119389
Data columns (total 32 columns):
 #   Column                          Non-Null Count   Dtype  
---  ------                          --------------   -----  
 0   hotel                           119390 non-null  object 
 1   is_canceled                     119390 non-null  int64  
 2   lead_time                       119390 non-null  int64  
 3   arrival_date_year               119390 non-null  int64  
 4   arrival_date_month              119390 non-null  object 
 5   arrival_date_week_number        119390 non-null  int64  
 6   arrival_date_day_of_month       119390 non-null  int64  
 7   stays_in_weekend_nights         119390 non-null  int64  
 8   stays_in_week_nights            119390 non-null  int64  
 9   adults                          119390 non-null  int64  
 10  children                        119386 non-null  float64
 11  babies                          119390 non-null  int64  
 12  meal                            119390 non-null  object 
 13  country                         118902 non-null  object 
 14  distribution_channel            119390 non-null  object 
 15  is_repeated_guest               119390 non-null  int64  
 16  previous_cancellations          119390 non-null  int64  
 17  previous_bookings_not_canceled  119390 non-null  int64  
 18  reserved_room_type              119390 non-null  object 
 19  assigned_room_type              119390 non-null  object 
 20  booking_changes                 119390 non-null  int64  
 21  deposit_type                    119390 non-null  object 
 22  days_in_waiting_list            119390 non-null  int64  
 23  customer_type                   119390 non-null  object 
 24  adr                             119390 non-null  float64
 25  required_car_parking_spaces     119390 non-null  int64  
 26  total_of_special_requests       119390 non-null  int64  
 27  reservation_status_date         119390 non-null  object 
 28  name                            119390 non-null  object 
 29  email                           119390 non-null  object 
 30  phone-number                    119390 non-null  object 
 31  credit_card                     119390 non-null  object 
dtypes: float64(2), int64(16), object(14)
memory usage: 29.1+ MB

 

특정 호텔의 숙박 관련 데이터인 것 같다.

 

10만개 이상의 row와 32개의 column을 가지고 있다.

  • 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: 카드번호

column이 많은만큼 필요 없는 데이터도 있을 것이다.

 

reservation_status_date의 경우 숙박 예정일이 아니라 예약을 접수한 날짜이다.

 

lead_time과 arrival데이터가 reservation_status_date에 대한 정보를 포함하고 있기 때문에 지우도록 한다.

 

이름, 이메일, 휴대폰번호, 신용카드정보는 예약 취소 여부와 관련이 없기 때문에 지운다.

# 필요없는 column 제거
hotel_df.drop(['reservation_status_date', 'name', 'email', 'phone-number', 'credit_card'], axis=1, inplace=True)

 

# 수치 정보
hotel_df.describe()

output>>

 

lead_time의 max가 737이다. 737일 전에 예약을 했다는 의미이다. 이상치인지 의심되기 때문에 확인을 해봐야한다.


1-2. lead_time

# 데이터 시각화
sns.displot(hotel_df['lead_time'])

output>>

# 데이터 시각화
sns.boxplot(hotel_df['lead_time'])

output>>

600일 까지도 굉장히 연속적으로 값이 존재하기 때문에 737정도면.. 충분히 가능성 있다고 판단해도 될 것 같다.

 


1-3. distribution_channel

예약한 방식에 따라 취소율이 다를 수 있으니 확인해보자.

# 데이터 시각화
sns.barplot(x=hotel_df['distribution_channel'], y=hotel_df['is_canceled'])

output>>

직접 예약보다는 대행사(TA/TO) 예약의 취소율이 더 높다고 보여진다.


1-4. hotel

호텔 종류도 취소율과 연관이 있는지 확인해본다.

# 데이터 시각화
sns.barplot(x=hotel_df['hotel'], y=hotel_df['is_canceled'])

output>>

휴양지 호텔보다 도시 호텔이 취소율이 더 높다. 


1-5. arrival_date_month

휴양지의 경우 성수기 비성수기에 따라 취소율이 다를 것으로 예상된다.

plt.figure(figsize=(15, 5))
sns.barplot(x=hotel_df['arrival_date_month'], y=hotel_df['is_canceled'])

output>>

만약 월별 데이터를 순서대로 보고 싶다면 calendar 모듈과 옵션을 통해 정렬할 수 있다.

 

import calendar

months = []

for i in range(1, 13):
    months.append(calendar.month_name[i])


plt.figure(figsize=(15, 5))
sns.barplot(x=hotel_df['arrival_date_month'], y=hotel_df['is_canceled'], order=months)

output>>


1-6. is_repeated_guest

재방문인지 아닌지에 대한 데이터이다.

# 데이터 시각화
sns.barplot(x=hotel_df['is_repeated_guest'], y=hotel_df['is_canceled'])

output>>

첫 방문인 손님의 취소율이 훨씬 높다.


1-7. deposit_type

요금 납부 방식에 대한 데이터이다.

# 데이터 시각화
sns.barplot(x=hotel_df['deposit_type'], y=hotel_df['is_canceled'])

output>>

취소율과 많은 관계가 있는 것으로 보인다.


1-8. corr()

지금까지는 종속변수와 독립변수간의 관계를 그래프로 하나하나 확인하였다.

 

상관관계를 보는 방법중 하나인 heatmap을 사용해보자.

# corr(): 열들 간의 상관관계를 계산하는 함수. 피어슨 상관계수
# -1 ~ 1 의 범위를 가지며 0에 가까울수록 두 변수의 상관관계가 없거나 매우 약함.

plt.figure(figsize=(15, 15))
sns.heatmap(hotel_df.corr(), cmap='coolwarm', vmax=1, vmin=-1, annot=True)

output>>


2. 결측치 처리

# 결측치 평균
hotel_df.isna().mean()

output>>

hotel                             0.000000
is_canceled                       0.000000
lead_time                         0.000000
arrival_date_year                 0.000000
arrival_date_month                0.000000
arrival_date_week_number          0.000000
arrival_date_day_of_month         0.000000
stays_in_weekend_nights           0.000000
stays_in_week_nights              0.000000
adults                            0.000000
children                          0.000034
babies                            0.000000
meal                              0.000000
country                           0.004087
distribution_channel              0.000000
is_repeated_guest                 0.000000
previous_cancellations            0.000000
previous_bookings_not_canceled    0.000000
reserved_room_type                0.000000
assigned_room_type                0.000000
booking_changes                   0.000000
deposit_type                      0.000000
days_in_waiting_list              0.000000
customer_type                     0.000000
adr                               0.000000
required_car_parking_spaces       0.000000
total_of_special_requests         0.000000
dtype: float64

 

children, country에 na가 존재한다.


2-1. country

country의 na는 특정 데이터로 대체하기가 힘들기 때문에 삭제한다.

hotel_df['country'].unique()

output>>

array(['PRT', 'GBR', 'USA', 'ESP', 'IRL', 'FRA', nan, 'ROU', 'NOR', 'OMN',
       'ARG', 'POL', 'DEU', 'BEL', 'CHE', 'CN', 'GRC', 'ITA', 'NLD',
       'DNK', 'RUS', 'SWE', 'AUS', 'EST', 'CZE', 'BRA', 'FIN', 'MOZ',
       'BWA', 'LUX', 'SVN', 'ALB', 'IND', 'CHN', 'MEX', 'MAR', 'UKR',
       'SMR', 'LVA', 'PRI', 'SRB', 'CHL', 'AUT', 'BLR', 'LTU', 'TUR',
       'ZAF', 'AGO', 'ISR', 'CYM', 'ZMB', 'CPV', 'ZWE', 'DZA', 'KOR',
       'CRI', 'HUN', 'ARE', 'TUN', 'JAM', 'HRV', 'HKG', 'IRN', 'GEO',
       'AND', 'GIB', 'URY', 'JEY', 'CAF', 'CYP', 'COL', 'GGY', 'KWT',
       'NGA', 'MDV', 'VEN', 'SVK', 'FJI', 'KAZ', 'PAK', 'IDN', 'LBN',
       'PHL', 'SEN', 'SYC', 'AZE', 'BHR', 'NZL', 'THA', 'DOM', 'MKD',
       'MYS', 'ARM', 'JPN', 'LKA', 'CUB', 'CMR', 'BIH', 'MUS', 'COM',
       'SUR', 'UGA', 'BGR', 'CIV', 'JOR', 'SYR', 'SGP', 'BDI', 'SAU',
       'VNM', 'PLW', 'QAT', 'EGY', 'PER', 'MLT', 'MWI', 'ECU', 'MDG',
       'ISL', 'UZB', 'NPL', 'BHS', 'MAC', 'TGO', 'TWN', 'DJI', 'STP',
       'KNA', 'ETH', 'IRQ', 'HND', 'RWA', 'KHM', 'MCO', 'BGD', 'IMN',
       'TJK', 'NIC', 'BEN', 'VGB', 'TZA', 'GAB', 'GHA', 'TMP', 'GLP',
       'KEN', 'LIE', 'GNB', 'MNE', 'UMI', 'MYT', 'FRO', 'MMR', 'PAN',
       'BFA', 'LBY', 'MLI', 'NAM', 'BOL', 'PRY', 'BRB', 'ABW', 'AIA',
       'SLV', 'DMA', 'PYF', 'GUY', 'LCA', 'ATA', 'GTM', 'ASM', 'MRT',
       'NCL', 'KIR', 'SDN', 'ATF', 'SLE', 'LAO'], dtype=object)

2-2. dropna()

# 결측치 제거
hotel_df = hotel_df.dropna()

3. column 합치기(파생변수)

데이터 전처리에는 여러가지 방법이 있다.

 

합쳐도 되는 column을 합치는 방법을 사용한다.

3-1. people

# 데이터 개수
len(hotel_df[(hotel_df['adults'] == 0) & (hotel_df['children'] == 0) & (hotel_df['babies'] == 0)])

 

호텔에 숙박하는 사람에 해당하는 column으로 'adults', 'children', 'babies'가 있다. 모두 0인 데이터가 170개 존재하기 때문에 세 컬럼을 합치고 0인 데이터는 지우도록 한다.

 

# 새 컬럼 생성
hotel_df['people'] = hotel_df['adults'] + hotel_df['children'] + hotel_df['babies']
# people이 0인 데이터를 제외하고 다시 저장
hotel_df = hotel_df[hotel_df['people'] != 0]

len(hotel_df[hotel_df['people'] == 0])

output>>

0

3-2. total_nights

people과 마찬가지로 총 숙박 일수 column을 (주중 숙박일 + 주말 숙박일)로 하여 생성한다.

 

# total_nights
hotel_df['total_nights'] = hotel_df['stays_in_week_nights'] + hotel_df['stays_in_weekend_nights']

# 숙박일이 0일인 데이터
len(hotel_df[hotel_df['total_nights'] == 0])

output>>

640

 

숙박일이 0일인 경우를 가능한 경우로 볼 수 있다고 판단하여 지우지 않고 넘어간다.


3-3. season

아까전에 확인한 arrival_date_month를 계절별 데이터로 바꿔서 저장해보자.

 

# apply, lambda 사용
hotel_df['season'] = hotel_df['arrival_date_month'].apply(lambda data: 'winter' if data in ['December', 'January', 'February'] else 'spring' if data in ['March', 'April', 'May'] else 'summer' if data in ['June', 'July', 'August'] else 'fall' if data in ['September', 'October', 'November'] else 'winter')

단순하게 apply와 lambda함수를 사용해서 파생변수를 만들 수 있다.

 

# calendar, map() 사용
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)

calendar 모듈과 map()함수를 사용해서 파생변수를 만들 수 있다.

 

# 요약 정보
hotel_df.info()

output>>

<class 'pandas.core.frame.DataFrame'>
Int64Index: 118728 entries, 0 to 119389
Data columns (total 30 columns):
 #   Column                          Non-Null Count   Dtype  
---  ------                          --------------   -----  
 0   hotel                           118728 non-null  object 
 1   is_canceled                     118728 non-null  int64  
 2   lead_time                       118728 non-null  int64  
 3   arrival_date_year               118728 non-null  int64  
 4   arrival_date_month              118728 non-null  object 
 5   arrival_date_week_number        118728 non-null  int64  
 6   arrival_date_day_of_month       118728 non-null  int64  
 7   stays_in_weekend_nights         118728 non-null  int64  
 8   stays_in_week_nights            118728 non-null  int64  
 9   adults                          118728 non-null  int64  
 10  children                        118728 non-null  float64
 11  babies                          118728 non-null  int64  
 12  meal                            118728 non-null  object 
 13  country                         118728 non-null  object 
 14  distribution_channel            118728 non-null  object 
 15  is_repeated_guest               118728 non-null  int64  
 16  previous_cancellations          118728 non-null  int64  
 17  previous_bookings_not_canceled  118728 non-null  int64  
 18  reserved_room_type              118728 non-null  object 
 19  assigned_room_type              118728 non-null  object 
 20  booking_changes                 118728 non-null  int64  
 21  deposit_type                    118728 non-null  object 
 22  days_in_waiting_list            118728 non-null  int64  
 23  customer_type                   118728 non-null  object 
 24  adr                             118728 non-null  float64
 25  required_car_parking_spaces     118728 non-null  int64  
 26  total_of_special_requests       118728 non-null  int64  
 27  people                          118728 non-null  float64
 28  total_nights                    118728 non-null  int64  
 29  season                          118728 non-null  object 
dtypes: float64(3), int64(17), object(10)
memory usage: 28.1+ MB

3-4. expected_room_type

희망한 방과 실제 예약된 방이 다른 경우 예약 취소를 할 가능성이 있다.

 

희망한 방과 예약된 방의 일치 여부를 파생컬럼으로 만들어보자.

 

# 방 일치 여부
hotel_df['expected_room_type'] = (hotel_df['reserved_room_type'] == hotel_df['assigned_room_type']).astype(int)

output>>

 

일치하면 1 다르면 0


3-5. cancel_rate

예약을 취소한 횟수와 정상 숙박한 횟수를 합하면 예약을 시도한 총 횟수가 된다.

 

예약을 한 횟수에 대한 예약 취소 비율을 계산하면 이 고객이 취소할 확률과 비슷한 데이터를 얻을 수 있다.

# 예약 취소 확률
hotel_df['cancel_rate'] = hotel_df['previous_cancellations'] / (hotel_df['previous_cancellations'] + hotel_df['previous_bookings_not_canceled'])

output>>

 

생성된 컬럼의 값을 보면 NaN이 많은걸 확인할 수 있다.

 

첫 방문이거나 예약을 취소한 데이터가 NaN이면 해당 계산 값이 NaN이 된다.

 

NaN을 머신러닝에서 사용하려면 값을 어떠한 의미도 되지 않는 값으로 대체해야한다.

 

여기선 -1이 적당할 것 같다.

# na 대체
hotel_df['cancel_rate'] = hotel_df['cancel_rate'].fillna(-1)

4. One Hot Encoding

 

# 요약 정보
hotel_df.info()

output>>

<class 'pandas.core.frame.DataFrame'>
Int64Index: 118728 entries, 0 to 119389
Data columns (total 32 columns):
 #   Column                          Non-Null Count   Dtype  
---  ------                          --------------   -----  
 0   hotel                           118728 non-null  object 
 1   is_canceled                     118728 non-null  int64  
 2   lead_time                       118728 non-null  int64  
 3   arrival_date_year               118728 non-null  int64  
 4   arrival_date_month              118728 non-null  object 
 5   arrival_date_week_number        118728 non-null  int64  
 6   arrival_date_day_of_month       118728 non-null  int64  
 7   stays_in_weekend_nights         118728 non-null  int64  
 8   stays_in_week_nights            118728 non-null  int64  
 9   adults                          118728 non-null  int64  
 10  children                        118728 non-null  float64
 11  babies                          118728 non-null  int64  
 12  meal                            118728 non-null  object 
 13  country                         118728 non-null  object 
 14  distribution_channel            118728 non-null  object 
 15  is_repeated_guest               118728 non-null  int64  
 16  previous_cancellations          118728 non-null  int64  
 17  previous_bookings_not_canceled  118728 non-null  int64  
 18  reserved_room_type              118728 non-null  object 
 19  assigned_room_type              118728 non-null  object 
 20  booking_changes                 118728 non-null  int64  
 21  deposit_type                    118728 non-null  object 
 22  days_in_waiting_list            118728 non-null  int64  
 23  customer_type                   118728 non-null  object 
 24  adr                             118728 non-null  float64
 25  required_car_parking_spaces     118728 non-null  int64  
 26  total_of_special_requests       118728 non-null  int64  
 27  people                          118728 non-null  float64
 28  total_nights                    118728 non-null  int64  
 29  season                          118728 non-null  object 
 30  expected_room_type              118728 non-null  int64  
 31  cancel_rate                     118728 non-null  float64
dtypes: float64(4), int64(18), object(10)
memory usage: 29.9+ MB

 

One Hot Encoding을 진행하기 전 object 타입의 컬럼들을 확인해보자.

obj_list = []

for i in hotel_df.columns:
    if hotel_df[i].dtype == 'O':
        obj_list.append(i)
        
obj_list



for i in obj_list:
    print(i, hotel_df[i].nunique())

output>>

['hotel',
 'arrival_date_month',
 'meal',
 'country',
 'distribution_channel',
 'reserved_room_type',
 'assigned_room_type',
 'deposit_type',
 'customer_type',
 'season']
 
 
hotel 2
arrival_date_month 12
meal 5
country 177
distribution_channel 5
reserved_room_type 9
assigned_room_type 11
deposit_type 3
customer_type 4
season 4

 

hotel은 앞에서 확인했듯이 resort, city로 나뉜다.

 

arrival_date_month의 경우 1월부터 12월까지를 영어로 나타낸 것이다. season이라는 파생컬럼을 만들었기 때문에 지워도 상관없을 것 같다.

 

meal은 식사 정보이다. 식사정보가 취소여부에 영향을 줄 것 같지 않기 때문에 지우도록 한다.

 

country는 177개로 다소 많은 데이터를 가지고 있기 때문에 One Hot Encoding을 하게 되면 column이 너무 많아진다. 그리고 나라 데이터 또한 취소여부와 큰 관련이 없을 것으로 판단하여 지우도록 한다.

 

나머지 데이터들은 크기가 적당하니 모두 One Hot Encoding을 진행한다.

 

hotel_df.drop(['country', 'meal'], axis=1, inplace=True)
obj_list.remove('country')
obj_list.remove('meal')


hotel_df = pd.get_dummies(hotel_df, columns=obj_list)

hotel_df.info()

output>>

<class 'pandas.core.frame.DataFrame'>
Int64Index: 118728 entries, 0 to 119389
Data columns (total 72 columns):
 #   Column                          Non-Null Count   Dtype  
---  ------                          --------------   -----  
 0   is_canceled                     118728 non-null  int64  
 1   lead_time                       118728 non-null  int64  
 2   arrival_date_year               118728 non-null  int64  
 3   arrival_date_week_number        118728 non-null  int64  
 4   arrival_date_day_of_month       118728 non-null  int64  
 5   stays_in_weekend_nights         118728 non-null  int64  
 6   stays_in_week_nights            118728 non-null  int64  
 7   adults                          118728 non-null  int64  
 8   children                        118728 non-null  float64
 9   babies                          118728 non-null  int64  
 10  is_repeated_guest               118728 non-null  int64  
 11  previous_cancellations          118728 non-null  int64  
 12  previous_bookings_not_canceled  118728 non-null  int64  
 13  booking_changes                 118728 non-null  int64  
 14  days_in_waiting_list            118728 non-null  int64  
 15  adr                             118728 non-null  float64
 16  required_car_parking_spaces     118728 non-null  int64  
 17  total_of_special_requests       118728 non-null  int64  
 18  people                          118728 non-null  float64
 19  total_nights                    118728 non-null  int64  
 20  expected_room_type              118728 non-null  int64  
 21  cancel_rate                     118728 non-null  float64
 22  hotel_City Hotel                118728 non-null  uint8  
 23  hotel_Resort Hotel              118728 non-null  uint8  
 24  arrival_date_month_April        118728 non-null  uint8  
 25  arrival_date_month_August       118728 non-null  uint8  
 26  arrival_date_month_December     118728 non-null  uint8  
 27  arrival_date_month_February     118728 non-null  uint8  
 28  arrival_date_month_January      118728 non-null  uint8  
 29  arrival_date_month_July         118728 non-null  uint8  
 30  arrival_date_month_June         118728 non-null  uint8  
 31  arrival_date_month_March        118728 non-null  uint8  
 32  arrival_date_month_May          118728 non-null  uint8  
 33  arrival_date_month_November     118728 non-null  uint8  
 34  arrival_date_month_October      118728 non-null  uint8  
 35  arrival_date_month_September    118728 non-null  uint8  
 36  distribution_channel_Corporate  118728 non-null  uint8  
 37  distribution_channel_Direct     118728 non-null  uint8  
 38  distribution_channel_GDS        118728 non-null  uint8  
 39  distribution_channel_TA/TO      118728 non-null  uint8  
 40  distribution_channel_Undefined  118728 non-null  uint8  
 41  reserved_room_type_A            118728 non-null  uint8  
 42  reserved_room_type_B            118728 non-null  uint8  
 43  reserved_room_type_C            118728 non-null  uint8  
 44  reserved_room_type_D            118728 non-null  uint8  
 45  reserved_room_type_E            118728 non-null  uint8  
 46  reserved_room_type_F            118728 non-null  uint8  
 47  reserved_room_type_G            118728 non-null  uint8  
 48  reserved_room_type_H            118728 non-null  uint8  
 49  reserved_room_type_L            118728 non-null  uint8  
 50  assigned_room_type_A            118728 non-null  uint8  
 51  assigned_room_type_B            118728 non-null  uint8  
 52  assigned_room_type_C            118728 non-null  uint8  
 53  assigned_room_type_D            118728 non-null  uint8  
 54  assigned_room_type_E            118728 non-null  uint8  
 55  assigned_room_type_F            118728 non-null  uint8  
 56  assigned_room_type_G            118728 non-null  uint8  
 57  assigned_room_type_H            118728 non-null  uint8  
 58  assigned_room_type_I            118728 non-null  uint8  
 59  assigned_room_type_K            118728 non-null  uint8  
 60  assigned_room_type_L            118728 non-null  uint8  
 61  deposit_type_No Deposit         118728 non-null  uint8  
 62  deposit_type_Non Refund         118728 non-null  uint8  
 63  deposit_type_Refundable         118728 non-null  uint8  
 64  customer_type_Contract          118728 non-null  uint8  
 65  customer_type_Group             118728 non-null  uint8  
 66  customer_type_Transient         118728 non-null  uint8  
 67  customer_type_Transient-Party   118728 non-null  uint8  
 68  season_fall                     118728 non-null  uint8  
 69  season_spring                   118728 non-null  uint8  
 70  season_summer                   118728 non-null  uint8  
 71  season_winter                   118728 non-null  uint8  
dtypes: float64(4), int64(18), uint8(50)
memory usage: 26.5 MB

완성


5. train-test-split

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=2023)

print(X_train.shape, y_train.shape)

print(X_test.shape, y_test.shape)

output>>

(83109, 71) (83109,)

(35619, 71) (35619,)

6. 랜덤 포레스트(Random Forest)

from sklearn.ensemble import RandomForestClassifier

# 랜덤 포레스트 분류기
rf = RandomForestClassifier()

rf.fit(X_train, y_train)

pred1 = rf.predict(X_test)

proba1 = rf.predict_proba(X_test)

# 확률 확인
print(proba1)

output>>

[[0.99       0.01      ]
 [0.91       0.09      ]
 [0.98       0.02      ]
 ...
 [0.295      0.705     ]
 [0.9675     0.0325    ]
 [0.24633892 0.75366108]]

7. 성능 평가

2023.12.27 - [AI/머신러닝] - [머신러닝] Confusion Matrix, AUC & ROC

 

[머신러닝] Confusion Matrix, AUC & ROC

혼돈행렬 선형 모델의 성능은 MSE, MAE, RMSE등으로 평가된다. 분류 모델은 Confusion Matrix(혼돈 행렬)를 사용하여 Perfomance Test를 한다. 혼돈 행렬을 사용하여 정밀도(Precision), 재현률(Recall), 정확도(Accur

caramelbottle.tistory.com

 

이진 분류 문제의 성능을 평가하기 위해선 ROC, AUC를 사용한다.

from sklearn.metrics import accuracy_score, confusion_matrix, classification_report, roc_auc_score

print('accuracy_score: ', accuracy_score(y_test, pred1))

print('confusion_matrix: \n', confusion_matrix(y_test, pred1))

print(classification_report(y_test, pred1))

output>>

accuracy_score:  0.8589516830904854
confusion_matrix: 
 [[20824  1611]
 [ 3413  9771]]
              precision    recall  f1-score   support

           0       0.86      0.93      0.89     22435
           1       0.86      0.74      0.80     13184

    accuracy                           0.86     35619
   macro avg       0.86      0.83      0.84     35619
weighted avg       0.86      0.86      0.86     35619

7-1. roc_auc_score

roc_auc_score(y_test, proba1[:, 1])

output>>

0.9258522784132585

 


7-2. 하이퍼 파라미터 수정(max_depth=30)

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

output>>

0.9282014901868613

 

적용전과 적용후의 AUC Score 비교를 통해 성능 차이를 볼 수 있다.

적용 전               적용후
0.9268826941531199 - 0.9282014901868613

7-3. ROC-AUC 시각화

import matplotlib.pyplot as plt
from sklearn.metrics._plot.roc_curve import roc_curve

# fpr = False Positive Rate
# tpr = True Positive Rate
# thr = Threshold
fpr, tpr, thr = roc_curve(y_test, proba2[:, 1])

plt.plot(fpr, tpr, label='ROC Curve')
plt.plot([0, 1], [0, 1])
plt.show()

output>>

 

댓글