[My IT : Codes] Hotel Booking Demand Datasets 분석(1)(데이터셋 불러오기~ 이상치/결측치 처리)

2026. 2. 13. 16:30·My IT/Codes

목표 : 데이터 셋을 분석해 호텔 예약 취소에 영향을 주는 요인들에는 무엇이 있는지 찾아보기

목차

1. 데이터셋 설명

2. 코드 & 설명

  • 데이터셋 불러오기
  • 이상치/결측치 처리
  • 특징에 따른 취소율 분석

3. 결론 도출

 

Dataset 설명

이 데이터는 Kaggle의 Hotel Booking Demand Datasets를 가져와 기본적으로 일부 수정을 가한 데이터로, 캐글에서 100% 동일하지는 않다. 2015.07.01 ~ 2017.08.31까지의 Resort Hotel과 City Hotel의 예약데이터를 포함하고 있다고 한다. 더 자세한 설명은 Dataset을 불러오면서 파악해보도록 하자.

 

Import

데이터 셋을 이용하기 위한 pandas, 시각화를 위한 matplotlib.pyplot과 seaborn을 import하였다.

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

 

 

Dataset 읽어오기

#dataset 읽어오기
df=pd.read_csv('hotel_data_modified.csv')
#dataset 정보 파악
df.info()

*결과

여기서 Columns에 대해 간략히 설명하자면

  • hotel : 호텔명(City Hotel/Resort Hotel)
  • is_canceled : 호텔 예약이 취소되었는지(1)/취소되지 않았는지(0)
  • lead_time : 호텔 예약 시점부터 고객의 호텔 도착 시점까지의 기간
  • arrival_date_year : 고객의 호텔의 도착 연도
  • arrival_date_month : 고객의 호텔의 도착 월
  • arrival_date_week_number : 고객의 호텔 도착 주 (ex. 8월 셋째 주에 도착 -> arrival_date_week_number = 3)
  • arrival_date_day_of_month: 고객의 호텔 도착 일(ex. 1월 6일에 도착 -> arrival_date_day_of_month = 6)
  • stays_in_weekend_nights : 고객이 호텔에 숙박했거나 예약한 주말 밤 수 (토요일~일요일)
  • stays_in_week_nights : 고객이 호텔에 숙박했거나 예약한 주중 밤 수(월요일~ 금요일)
  • adults : 예약된 어른의 수
  • children : 예약된 어린이의 수
  • babies : 예약된 아기의 수
  • meal : 예약된 식사 유형
  • country : 투숙객의 출신 국가, 국가표기코드 형식으로 표기(ex. ISO 3166-2:KR)
  • market_segment : 고객 유형
  • distribution_channel : 예약 유통 채널
  • is_repeated_guest : 이전에 방문을 했던 고객이라면 1, 아니라면 0
  • previous_cancellations : 현재 예약 이전에 고객이 취소한 이전 예약 수
  • previous_bookings_not_canceled : 현재 예약 이전에 고객이 취소하지 않은 이전 예약 수
  • reserved_room_type : 예약한 룸 타입 코드
  • assigned_room_type : 배정된 룸 타입 코드, reserved_room_code와 다르다면호텔 운영상의 이유(ex.초과 예약) 또는 고객 요청으로 인해 다른 객실이 배정되는 경우이다.
  • agent : 예약을 진행한 여행사의 ID
  • company : 예약을 하였거나 예약금을 지불할 책임이 있는 회사 또는 단체의 ID
  • days_in_waiting_list : 예약이 확정되기 전까지 해당 예약이 예약 대기자 명단에 있었던 일 수
  • required_car_parking_spaces : 고객이 요구하는 주차 공간 수
  • total_of_special_requests : 고객의 특별 요청 건수(ex. 트윈 베드 , 아기 침대 등)
  • reservation_status : 예약의 마지막 상태(Canceled, Check-Out, No-Show)
  • reservations_status_date: 마지막 예약 상태(reservation_status)가 설정된 날짜

 

결측치/이상치 처리

Children 결측치 처리

먼저 결측치 처리를 진행하는데, 결측치를 파악하기 위해서 isna() 메소드를 이용하여 Nan값이 있는 Column을 찾았다.

#혹시 결측치가 있을 수 있으니 isna()로 결측치 파악
null_columns = df.columns[df.isna().any()]

 

이후 한 Column씩 결측치 처리를 시작했는데, 먼저 children Column부터 시작했다.

df['children'].value_counts(dropna=False) # children column value 갯수 파악

Nan값이 4개 존재하는걸 볼 수 있다

  • children column 결측치는 수가 많지 않기도 하고 , 조사시에 0이라 안 적었을 확률이 높다고 판단해 0으로 처리
  • 결측치 처리 과정에서 10.0이라는 이상치 발견하여 children column 이상치 처리(0으로 변환) -> 물론 진짜 어린이를 10명 데리고 왔을 수도 있겠지만, 많은 자료를 다뤄야 하기 때문에 이렇게 드문 케이스는 배제했다.
  • 원본 데이터는 건드리지 않기 위해서 df_mv 라는 새로운 DataFrame을 할당해서 코드를 진행했다.
df['children'] = df['children'].replace({10.0 : 0.0}) #이상치 10 replace
df_mv = df.fillna({'children' : 0.0}) #float형에 맞춰 fill

 

Country, Agent, Company Column 결측치 처리

  • country column의 결측치는 따로 대체할 값이 없다고 판단, drop하기로 결정하였다.
  • agent, company의 nan값은 여행사/회사가 없는 것이라고 판단해 0으로 fill하였다.
#contry column 결측치 처리
df_mv = df_mv.dropna(subset = ['country'])
df_mv[['agent', 'company']] = df_mv[['agent', 'company']].fillna(0.0)

 

코드 실행 이후 

df_mv[null_columns].isna().sum()

위의 코드를 실행하면,

위와 같은 표가 나오며 결측치가 잘 처리된 것을 볼 수 있다.

이제 이상치를 처리할 차례인데, 그 전에 agent, company id 로는 현재는 agent/company의 유무 밖에 판단할 수 있는 정보가 없다고 판단해 값이 있으면 1, 없으면 0으로 재편성 하여 추후에 계산이 쉽도록 처리했다.

#agent, company column 유무 판단으로 0/1로 바꾸기
df_mv['has_agent'] = (df_mv['agent'] > 0).astype(int)
df_mv['has_company'] = (df_mv['company'] > 0).astype(int)
#본래 agent, compay column 삭제
df_mv = df_mv.drop(['agent', 'company'], axis = 1)

 

총 방문인원으로 이상치 처리

이제 이상치를 분류할 차례인데, 먼저 총 방문 인원에 따른 이상치를 처리했다. 방문 인원이 너무 많거나, 방문 인원이 0명이면 이는 잘못된 정보이므로 이상치 정보로 분류하였다.

#예약된 총 사람의 수가 0명이면, 잘못된 정보이므로 이상치로 분류해 처리
df_mv['total_guests'] = df_mv['adults'] + df_mv['children'] + df_mv['babies'] #총 인원 column 생성
df_mv = df_mv.drop(df_mv[df_mv['total_guests'] == 0].index) #0인 행 삭제
df_mv['total_guests'].value_counts()

결과 : 

value_counts() 메소드로 인원 별 팀수를 파악했고, 5명 이상의 단체고객이나 너무 많은 사람 수를 쓴 고객들은 상한값을 5로 임의로 정해, 이상치 처리를 하였다.

 

#상한 처리
df_mv['total_guests'] = df_mv['total_guests'].apply(lambda x : 5 if x >5 else x)#apply()이용
df_mv['total_guests'].value_counts()

 

숙박일수에 따른 이상치 처리

총 숙박일수를 구하려면 예약한 주말 밤 수  + 주중 밤 수를 해야 하기 때문에 추가로 총 숙박일수를 보여주는 column을 추가하고, 총 숙박일수가 0일때는 drop, 상한 이상치 범위를 정하기 위해서 사분위수를 이용하였다.

# 총 숙박일수를 보여주는 column 추가
df_mv['total_nights'] = df_mv['stays_in_weekend_nights'] + df_mv['stays_in_week_nights']
df_mv = df_mv.drop(df_mv[df_mv['total_nights'] == 0].index) #0값 처리

#4분위수(quantile) 이용, 상한값 처리
iqr = df_mv['total_nights'].quantile(0.75) - df_mv['total_nights'].quantile(0.25)
up_total_nights = df_mv['total_nights'].quantile(0.75) + 1.5 * iqr

#apply()를 위한 상한값 처리 함수
def total_knight_upper(x):
    if x > up_total_nights :
      return up_total_nights
    else:
      return x
      
df_mv['total_nights'] = df_mv['total_nights'].apply(total_knight_upper)

위의 이상치 제거가 잘 되었는지 확인하기 위해 value_counts()를 쓰게되면 결과는 다음과 같이 나온다.

1~7까지(up_total_nights가 7인가보다) 이상치 없이 잘 분포된 것을 볼 수 있다.

 

예약 날짜(lead_time)에 따른 이상치 처리

예약 날짜의 이상치는 0일 경우에는 당일 예약이기때문에, 하한은 정하거나 하지 않고 , 장기 예약 고객들이 많기 때문에 먼저 상자그림으로 시각화를 한 후 이상치 상한값을 정하기로 하였다.

상자그림을 시각화 하기 위해서 plt.boxplot() 메소드를 사용하였다.

 

plt.figure(figsize=(10,5))
plt.boxplot(df_mv['lead_time'])
plt.show()

결과

위 그림을 보면 알 수 있듯이 임계값 위에도 꽤나 빼곡하게 데이터가 존재하는걸 볼 수 있고, 이 때문에 사분위수를 정할때는 보통 1.5를 곱하지만, lead_time의 경우에는 2를 곱하여 상한값을 조금 높게 잡았다.

#주로 1.5를 곱하지만 장기예약 고객이 많으므로 보다 크게 범위를 잡음
#lead_time이기 때문에 상한만 처리
iqr = df_mv['lead_time'].quantile(0.75) - df_mv['lead_time'].quantile(0.25)
up_lead_time = df_mv['lead_time'].quantile(0.75) + 2 * iqr #1.5 대신 2

#apply를 사용해 이상치 처리
def lead_time_upper(x):
    if x > up_lead_time :
      return up_lead_time
    else:
      return x
df_mv['lead_time'] = df_mv['lead_time'].apply(lead_time_upper)

 

'My IT > Codes' 카테고리의 다른 글

[My IT : Codes] LSTM 활용 Air Pollution Forecast 데이터셋 예측(1) 데이터셋 소개 ~ 모델링  (1) 2026.03.25
[My IT : Codes] AutoEncoder 활용 Denoising  (0) 2026.03.23
[My IT : Codes] Bank-Marketing 데이터 분석(2) (모델 비교 학습 ~ 결론 도출)  (1) 2026.03.09
[My IT : Codes]Bank-Marketing 데이터 분석(1) (데이터셋 설명 ~ 데이터 전처리)  (2) 2026.03.07
[My IT : Codes] Hotel Booking Demand Datasets 분석(2)(특징 분석~결론 도출)  (0) 2026.02.13
'My IT/Codes' 카테고리의 다른 글
  • [My IT : Codes] AutoEncoder 활용 Denoising
  • [My IT : Codes] Bank-Marketing 데이터 분석(2) (모델 비교 학습 ~ 결론 도출)
  • [My IT : Codes]Bank-Marketing 데이터 분석(1) (데이터셋 설명 ~ 데이터 전처리)
  • [My IT : Codes] Hotel Booking Demand Datasets 분석(2)(특징 분석~결론 도출)
uj07096
uj07096
개발블로그 시작 !
  • uj07096
    김재헌 님의 블로그
    uj07096
  • 전체
    오늘
    어제
    • 분류 전체보기 N
      • Algorithm
      • My IT
        • Article
        • Codes
      • TIL
      • My Projects N
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    딥러닝
    YOLO
    이상치
    LSTM
    DeepLearning
    AI
    EfficientNet
    transfer learning
    EDA
    코딩테스트
    Tensor
    til
    autoencoder
    python
    Faster R-CNN
    머신러닝
    PyTorch
    GAN
    Stack
    DenseNet
    kaggle
    optuna
    convolution
    데이터전처리
    ResNet
    코테
    프로그래머스
    Algorithm
    파이썬
    LeetCode
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
uj07096
[My IT : Codes] Hotel Booking Demand Datasets 분석(1)(데이터셋 불러오기~ 이상치/결측치 처리)
상단으로

티스토리툴바