AI/Machine Learning

[Machine Learning] Kaggle Competition 데이터 전처리 예제

byunghyun23 2022. 8. 26. 20:17

https://www.kaggle.com/competitions

 

Kaggle Competitions

 

www.kaggle.com

Kaggle은 2010년 설립된 예측모델 및 분석 대회 플랫폼입니다.

위의 링크인 Kaggle Competition으로 들어가시면 기업 또는 단체에서 등록한 머신러닝 문제에 도전할 수 있습니다.

 

Competition에 등록된 문제는 대부분 raw data이기 때문에 회귀 또는 분류 모델로 학습을 하기 위한 전처리 과정이 필수적입니다.

따라서 이전 포스팅을 기반으로 kaggle competition 데이터 전처리를 진행해보겠습니다.

 

https://www.kaggle.com/competitions/hotel-booking-demand-3

 

Hotel booking demand | Kaggle

 

www.kaggle.com

해당 competition은 호텔 이용자 데이터를 분석하여 호텔 예약이 취소될지 아닐지를 분류하는 머신러닝 알고리즘을 개발하는 것입니다.

 

데이터는 정답값(y)인 'is_canceled' 칼럼을 제외하여 총 28개의 칼럼으로 이루어져 있습니다.

데이터는 문자, 숫자, 날짜 등이 존재합니다.

먼저 문자 데이터는 기본적으로 학습에 사용할 수 없습니다.

'arrival_data_month' 칼럼은 1월부터 12월을 나타내고, 이것을 숫자로 바꿔줘야 합니다.

이 작업을 인코딩(encoding)이라고 부릅니다.

예를 들어 1월은 0, 2월은 1, 3월은 2, ... 12월은 11

이런식으로 문자를 숫자로 바꿀 수 있습니다. 이러한 방법은 label encoding이라고 부릅니다.

하지만 이러한 label encoding같은 경우에 1월은 0이고, 12월은 11이 됩니다.

1월과 12월은 날짜를 나타낼 뿐 둘 중 어느 달이 더 중요한 값인지는 말하기 어렵습니다.

머신러닝 모델이 학습을 진행할 때, 12월의 값인 11이 1월인 0보다 훨씬 큰 값이 때문에 모델의 예측이 편향될 수 있습니다.

 

따라서 이러한 경우는 one-hot encoding을 통해 0과 1로 데이터를 표현하는 것이 좀 더 좋습니다.

'arrival_data_month' 칼럼을 one-hot encoding할 경우 첫 번째 데이터인 'February'은 1월부터 12월까지를 순서대로 고려하여 [0 1 0 0 0 0 0 0 0 0 0 0] 와 같이 표현될 수 있습니다.

'February'가 2월이기 때문에 이해를 돕기 위해 위와 같이 표현했지만,

그 순서는 직접 지정할 수 있으며 sklearn이나 pandas 라이브러리를 이용하면 default는 문자의 알파벳 순서입니다.

 

데이터 인코딩을 위해서는 먼저 데이터를 살펴볼 필요가 있습니다.

칼럼별 unique 값을 확인해보겠습니다.

    for col in train_df.columns:
        print('=============== ' + col + ' ===============')
        print(train_df[col].unique())

hotel 칼럼은 문자이기 때문에 인코딩이 필수이며 unique 값이 'Resort hotel'과 'City hotel' 인것으로 볼 때, 순서의 의미가 없는 명목 데이터입니다. 또한 unique 값의 개수가 2개이기 때문에 이 경우에는 label encoding을 하겠습니다.

def label_encoding(in_df, column_list):
    out_df = in_df.copy()

    for col in column_list:
        le = LabelEncoder()
        value_data = out_df[col].values
        new_data = le.fit_transform(value_data)

        out_df[col] = new_data

    return out_df
    
new_train_df = label_encoding(train_df, ['hotel'])

label_encoding 함수는 data frame의 칼럼명을 리스트로 전달받아 해당하는 칼럼에 전부 label encoding을 적용합니다.

 

나머지 문자로된 칼럼 'country', 'market_segment' 등은 one-hot encoding을 적용합니다.

또한 'arrival_date_year' 칼럼은 연도를 나타내는 숫자이지만 그 숫자들의 순서가 서로 의미가 없고 2015년에서 2017년까지 총 3년으로 제한하고 있기 때문에 (competition description에 기재되어 있음) one-hot encoding을 적용합니다.

def onehot_encoding(in_df, column_list):
    out_df = in_df.copy()

    for col in column_list:
        new_data = pd.get_dummies((out_df[col]))

        for i, name in zip(range(len(out_df)), out_df.columns):
            if name == col:
                for n in new_data.columns:
                    out_df.insert(i, str(col)+'_'+str(n), new_data[n])
                break

        out_df.drop(col, axis=1, inplace=True)

    return out_df
    
new_train_df = onehot_encoding(new_train_df,
                               ['arrival_date_year', 'arrival_date_month',
                                'arrival_date_day_of_month', 'meal', 'country', 'market_segment',
                                'distribution_channel', 'reserved_room_type', 'assigned_room_type',
                                'deposit_type', 'customer_type'])

 

'lead_time' 칼럼과 같은 데이터는 숫자이며, 'arrival_data_year' 칼럼과 같이 유한개로 정해져있기 않기 때문에 encoding을 할 수 없습니다.

Encoding을 할 수 있는 경우는 어떠한 테스트 데이터를 예측에 사용하더라도 해당 칼럼의 도메인의 범위를 벗어나지 않는다는 것이 보장 될 때 입니다. ('arrival_data_year'은 칼럼은 훈련 및 테스트 데이터 모두 2015~2017으로 제한되어 있습니다.)

 

하지만 'lead_time' 칼럼의 값은 최솟값은 0이고 최댓값은 500을 넘습니다.

이렇게 데이터 값의 범위가 크면 모델 학습에 악영향을 줄 수 있습니다. (편향성)

 

Scaling 방법은 여러가지가 있지만, 여기서는 standard scaler를 사용하겠습니다.

def standard_scaling(in_df, column_list):
    out_df = in_df.copy()

    for col in column_list:
        std = StandardScaler()
        std.fit(out_df[[col]])
        new_data = std.transform(out_df[[col]])

        out_df[col] = new_data

    return out_df
    
new_train_df = standard_scaling(new_train_df,
                                ['lead_time', 'arrival_date_week_number', 'stays_in_weekend_nights',
                                 'stays_in_week_nights', 'adults', 'children', 'babies', 'previous_cancellations',
                                 'previous_bookings_not_canceled', 'booking_changes', 'days_in_waiting_list',
                                 'adr', 'required_car_parking_spaces', 'total_of_special_requests'])

 

'reservation_status_date' 칼럼을 제외하고 위와 같이 label encoding, one-hot encoding, standard scaling을 진행한 결과,

데이터셋의 27개의 칼럼이 271개가 되었습니다.

 

분류 모델에 전처리된 데이터를 사용하여 호텔 예약 취소 여부를 예측해보겠습니다.

사용된 모델은 xgboost classifier 입니다.

(훈련 및 검증 데이터 split 코드는 생략되었습니다.)

xg = XGBClassifier(gamma=0.5, learning_rate=0.03, max_depth=32, n_estimators=1000, silent=1)
xg.fit(X_train, y_train, early_stopping_rounds=20, eval_set=[(X_val, y_val)])
y_pred_xgb = xg.predict(X_val)

print('XGB Accuracy : %.4f' % accuracy_score(y_val, y_pred_xgb))
# XGB Accuracy : 0.8776