본문 바로가기
AI

랜덤 포레스트(데이터 전처리)

by 코낄2 2023. 12. 28.

1. hotel 데이터셋

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()

<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
  • 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: 카드번호
# 데이터 분석에 필요 없는 열 삭제
hotel_df.drop(['reservation_status_date', 'name', 'email', 'phone-number', 'credit_card'], axis=1, inplace=True)
hotel_df.describe()

sns.displot(hotel_df['lead_time'])

당일 예약이 많음

sns.boxplot(hotel_df['lead_time'])

700일 이전 예약은 약간 이상치로 생각해 볼 수 있습니다.

sns.barplot(x=hotel_df['distribution_channel'], y=hotel_df['is_canceled'])

Undefined의 취소율이 높지만, 심지가 길기 때문에 데이터가 적은 것을 의심해볼 수 있습니다.

hotel_df['distribution_channel'].value_counts()

TA/TO        97870
Direct       14645
Corporate     6677
GDS            193
Undefined        5
Name: distribution_channel, dtype: int64
sns.barplot(x=hotel_df['hotel'], y=hotel_df['is_canceled'])

sns.barplot(x=hotel_df['arrival_date_year'], y=hotel_df['is_canceled'])

연도별 취소율은 크게 차이나지 않습니다.

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

월별 취소율은 월마다 차이가 있어보이지만, 월이 순서대로 정돈되지 않아 데이터를 깔끔하게 보기가 어렵습니다.

- 도표에 표출 순서 정렬하기

import calendar

print(calendar.month_name[1]) // January
print(calendar.month_name[2]) // February 
print(calendar.month_name[3]) // March

calendar 모듈을 import 하면 month_name을 이용해 월의 이름을 순서대로 가져올 수 있습니다.

months = []

for i in range(1,13):
    months.append(calendar.month_name[i])
    
months
['January',
 'February',
 'March',
 'April',
 'May',
 'June',
 'July',
 'August',
 'September',
 'October',
 'November',
 'December']
# order=months로 정렬
plt.figure(figsize = (15,5))
sns.barplot(x=hotel_df['arrival_date_month'],y=hotel_df['is_canceled'],order=months)

추운 겨울쯤 취소율이 낮아짐

sns.barplot(x=hotel_df['is_repeated_guest'],y=hotel_df['is_canceled'])

재방문인 사람들의 취소율이 훨씬 낮다

sns.barplot(x=hotel_df['deposit_type'],y=hotel_df['is_canceled'])

당일 예약이 많아서 환불금액이 없는 고객의 취소율이 많게 나온 것으로 추정

hotel_df['deposit_type'].value_counts()
No Deposit    104641
Non Refund     14587
Refundable       162
Name: deposit_type, dtype: int64

✔️ corr()함수 : corr() 함수는 Pandas 라이브러리에서 제공하는 데이터프레임(DataFrame)의 열들 간 상관계수를 계산하는 메서드입니다. 상관계수는 두 변수 간의 선형 관계의 강도와 방향을 나타내는 통계적 지표입니다. 상관계수는 일반적으로 -1부터 1까지의 범위를 가지며, 0에 가까울수록 두 변수 간의 상관관계가 없거나 매우 약합니다. -1은 두 변수가 반비례 관계에 있을 때를 나타내며, 1은 두 변수가 비례하는 관계에 있을 때를 나타냅니다. "pearson" (기본값), "kendall", "spearman" 중 하나를 선택하여 각각 피어슨, 켄달, 스피어만 상관계수를 계산할 수 있습니다.

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

 

- 결측값 확인

hotel_df.isna().mean()

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
# NaN 비율이 워낙 작기때문에 과감하게 삭제
hotel_df= hotel_df.dropna()

- 이상치 확인

hotel_df[hotel_df['adults']==0]
// 393 rows 확인
hotel_df['people'] = hotel_df['adults']+hotel_df['children']+hotel_df['babies']
# 사람이 한명도 없는 데이터 삭제
hotel_df = hotel_df[hotel_df['people'] !=0 ]
hotel_df['total_nights'] = hotel_df['stays_in_week_nights'] + hotel_df['stays_in_weekend_nights']
hotel_df[hotel_df['total_nights']==0]
// 640 rows 확인

숙박은 아니고 대실 개념일 수 있기 때문에 total_nights가 0인 컬럼은 그대로 둡니다.

hotel_df.info()
<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

# 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

{'March': 'spring',
 'April': 'spring',
 'May': 'spring',
 'June': 'summer',
 'July': 'summer',
 'August': 'summer',
 'September': 'fall',
 'October': 'fall',
 'November': 'fall',
 'December': 'winter',
 'January': 'winter',
 'February': 'winter'}

# 딕셔너리 생성 후 map 함수 사용해서 한번에 적용

hotel_df['season'] = hotel_df['arrival_date_month'].map(new_season_dic)

 

- 예약한 룸 타입(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['cancel_rate'] = hotel_df['previous_cancellations'] / (hotel_df['previous_cancellations']+ hotel_df['previous_bookings_not_canceled'])
hotel_df[hotel_df['cancel_rate'].isna()]
//109523 rows

hotel_df['cancel_rate'] = hotel_df['cancel_rate'].fillna(-1)
# 첫방문인 사람들은 별도의 카테고리컬한 숫자를 넣어줌.

- 취소율의 결측값을 확인해보면, NaN값이 많은 것을 확인 해볼 수 있습니다. 이는 첫 방문자들의 취소율이 NaN 값으로 들어가 있기 때문입니다. 따라서 해당 NaN값은 카테고리컬한 값으로 채워줍니다.

숫자 -1을 사용하여 누락된 값을 나타내는 것은 일반적으로 "sentinel value" 또는 "flag value"를 사용하는 것입니다. 이는 특정한 목적을 나타내기 위해 선택된 특별한 카테고리컬한 값으로, 주로 데이터에서 누락된 값을 나타내거나 예외적인 상황을 표시하기 위해 사용됩니다. 

  1. 구분 가능성: -1은 일반적인 데이터 값과 다르기 때문에 누락된 값을 쉽게 식별할 수 있습니다.
  2. 분석 편의성: 데이터를 처리하거나 시각화할 때 특별한 값을 사용하면 해당 값에 대한 특별한 조치를 취할 수 있습니다.
  3. 모델 학습: 몇몇 머신 러닝 모델은 NaN과 같은 누락된 값을 처리하는 데 어려움을 겪을 수 있습니다. 특별한 값을 사용하면 모델이 해당 값을 쉽게 이해하고 처리할 수 있습니다.

그러나 -1을 사용하는 것은 주관적인 선택일 뿐이며, 데이터의 특성과 분석 목적에 따라 다를 수 있습니다. 다른 값이나 다른 방법을 사용하는 것도 가능합니다. 중요한 것은 해당 값이 분석 결과에 어떤 영향을 미칠지 고려하는 것입니다.

hotel_df.info()
<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
hotel_df['country'].dtype // dtype('O')
# object 타입은 대문자'O'로 나타냄

- Object 타입 확인해보기

obj_list = []

for i in hotel_df.columns:
    if hotel_df[i].dtype == 'O':
        obj_list.append(i)
        
obj_list
['hotel',
 'arrival_date_month',
 'meal',
 'country',
 'distribution_channel',
 'reserved_room_type',
 'assigned_room_type',
 'deposit_type',
 'customer_type',
 'season']
 
hotel_df[obj_list].nunique()
 
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
dtype: int64
# 취소율과 관련 없어보이는 행 제거
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.columns => 72개

 

'AI' 카테고리의 다른 글

랜덤 포레스트  (0) 2023.12.29
앙상블 모델  (0) 2023.12.29
서포트 벡터 머신  (0) 2023.12.28
로지스틱 회귀  (0) 2023.12.27
의사 결정 나무(자전거 대여 예제)  (0) 2023.12.26