머신러닝을 공부하게 되면 Titanic (이하 타이타닉호) 데이터를 처음 마주하는 경우가 많습니다. 타이타닉호 탑승객 정보가 속성으로 들어있는 고객 데이터를 기반으로 타이타닉호에서 생존을 했을까 안 했을까를 예측하는 모델을 생성하는 연습을 주로 하게 됩니다. 그다음 스텝으로 Kaggle에서 제공하는 Getting Started Prediction Competition인 Spaceship Titanic (우주선 타이타닉호)를 XGBRegressor를 이용해서 연습해보고자 합니다.
우주선 타이타닉호는 2912년에 태양계에서 다른 외계 행성으로 이주하기 위한 항해를 하고 있었습니다. 그러나 옛날에 타이타닉호와 비슷하게 거의 절반 가까이의 승객들이 다른 차원으로 이동해버렸다고 합니다. 손상된 컴퓨터 시스템 때문에 어떤 고객이 사라진 건지 완전한 기록은 없다고 합니다. 일부 기록에서 사라진 고객은 Transported 값이 True, 다른 차원으로 이동되지 않았다면 False로 표현이 되었고, 기록이 없는 고객의 Transported 값을 예측하는 것이 이번 competition의 내용입니다.
XGBoost는 예측 모델 여러개를 합쳐서 사용하는 앙상블 기법입니다. 그중 gradient boosting 기법으로 모델을 최적화하는데, 이는 처음에는 하나의 모델을 가지고 앙상블을 만들고 특정 사이클을 돌면서 앙상블에 모델을 하나씩 추가하는 방식입니다. 사이클은 예측 -> loss function 계산 -> 새로운 모델 train -> 앙상블에 새로운 모델 추가로 구성되어 있고, 우리는 loss function을 "점진적으로 줄이는(gradient descent)" 파라미터를 새로운 모델에 결정하게 됩니다.
실습을 위해 개인 장비의 Jupyter Notebook 키셨다면, 다음 링크에서 데이터를 다운로드해주세요. Kaggle Notebook을 여셨다면, 데이터는 별도의 다운로드가 필요 없으며 아래 코드를 활용해 데이터를 불러오기 가능합니다. 또한 Kaggle 플랫폼을 활용해 바로 예측 모델을 제출함으로써 한 번에 대회 참여가 가능합니다.
각종 필요한 라이브러리를 불러줍니다. 이 많은 from을 줄이는 방법에 대해서 알고 계신분이 있나요?
가장 핵심이 되는 train 데이터를 불러와줍니다. 저는 kaggle에서 제공하는 notebook을 사용할 예정이라서 데이터 불러오는 코드는 다음과 같습니다. 데이터를 불러왔다면 결측값 처리 등 데이터셋 전처리를 위해서 데이터를 이리저리 살펴보는 작업이 필요합니다. 위에서는 head로 살짝 들여다보고, describe(), len(), info()를 사용하여 컬럼의 Null값이 아닌 개수랑 데이터 타입을 자세하게 들여다볼 필요가 있습니다.
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error
from xgboost import XGBRegressor
from xgboost import XGBClassifier
# 데이터 불러오기
# kaggle jupyter notebook 버전
import os
for dirname, _, filename in os.walk('/kaggle/input'):
for filename in filenames:
print(os.path.join(dirname, filename))
dataset_df = pd.read_csv('/kaggle/input/spaceship-titanic/train.csv')
print('전체 train 데이터셋의 크기는 {}'.format(dataset_df.shape))
# 데이터셋 머리 뚜껑 까보기
dataset_df.head(5)
describe()를 통해 데이터셋의 숫자형 컬럼에 한해 대표 통계적 지표를 확인할 수 있습니다. count, mean, standard deviation, 백분율, 최고값을 알아낼 수 있고, 여기서 이상한 컬럼을 걸러낼 수 있겠지만, 우리는 연습용 데이터로 잘 정제된 데이터를 사용 중이기 때문에 count 값이 조금 제각각인 것을 확인하고 넘어갑니다.
dataset_df.describe()
count 값이 제각각이니 len()을 통해서 데이터셋 전체 길이는 얼마인지 확인합니다. len()에 맞는 count 값이 없었기 때문에 모든 숫자형 컬럼이 null값이 존재할 거라고 유추할 수 있겠네요.
len(dataset_df)
그럼 null값의 갯수를 확인할 수 있는 .info()까지 확인해 봅니다.
dataset_df.info()
우주선 타이타닉 예측 대회의 예측 target인 Trasported 여부를 그래프로 확인해 봅니다. 아래 그림처럼 거의 절반의 사람들이 사라진 것을 확인할 수 있습니다.
plot_df = dataset_df.Transported.value_counts()
plot_df.plot(kind='bar');
데이터를 간단하게 둘러보았고, 컬럼별로 histplot을 그려보면서 데이터 분포를 더 자세하게 둘러보아도 좋습니다. 혹은 kaggle 사이트를 활용해서 작업을 진행하신다면, Competition의 Data 탭에서 페이지 하단의 Data Explorer를 확인해 보는 것도 유용합니다. (Data Explorer 링크)
본격적으로 train 데이터를 훈련하기 위해서 X와 target y로 분리해 줍니다.
y = dataset_df.Transported
X = dataset_df.(['Transported'], axis=1)
X
모델에 데이터셋을 자유자재로 사용하기 위해서는 숫자형 컬럼과 아닌 컬럼을 잘 구분해서 다뤄줘야 합니다.
n = (X.dtypes == 'float64')
numeric_cols = list(n[n].index)
numeric_cols
머신러닝에서는 train데이터셋과 valid 데이터셋으로 나눠주는 작업이 필요한데, skit-learn에서 제공하는 모듈로 한 번에 처리합니다. 가장 무난한 8:2로 나누었고, random state을 지정해 주어 코드를 여러 번 돌려도 동일하게 데이터가 쪼개질 수 있도록 지정해 줍니다.
X_train, X_valid, y_train, y_valid = train_test_split(X, y, train_size=0.8, test_size=0.2, random_state=0)
숫자형이 아니고, 데이터가 카테고리처럼 몇 가지 구분되는 값으로 구성된 범주형 데이터를 별도로 처리해 줍니다. XGBRegressor가 범주형 데이터는 object타입으로 들어가게 되면 에러를 뱉어내기 때문에 해당 작업이 필요합니다. 저는 10가지 이하의 개수로 구분되는 object 타입의 컬럼을 범주형 데이터로 구분하여 범주형 데이터라는 표식을 해주겠습니다.
categorical_cols = [cname for cname in X_train.columns if
X_train[cname].dtype == 'object']
cat_attribs = categorical_cols
X_train[cat_attribs] = X_train[cat_attribs].astype('category')
X_valid[cat_attribs] = X_valid[cat_attribs].astype('category')
데이터 전처리가 완료되었다면, 모델 피팅을 해보겠습니다. XGBoost는 파라미터(=매개변수) 조절을 통해서 정확도랑 학습 속도를 변화시킬 수 있습니다.
# n_estimators
n_estimators는 위에서 말씀드린 대로 XGBoost가 앙상블기법이기 때문에 몇 개의 모델을 사이클마다 추가하면서 하나의 앙상블로 제작할 것이냐에 대한 매개변수입니다. 사이클마다 하나씩 모델을 추가하기 때문에 사이클 개수와도 동일합니다. 너무 낮다면, underfitting이 될 수 있고, 너무 높은 값은 overfitting이 될 수 있다고 합니다. 일반적으로는 100에서 1000 사이의 값을 넣는다고 합니다.
# early_stopping_rounds
early_stopping_rounds를 지정해 줌으로써 가장 이상적인 n_estimators를 자동으로 찾을 수 있습니다. Validation scores 값이 개선되지 않을 때에, n_estimators 수치에 도달하지 않더라도 모델이 일찍 멈출 수 있는 값입니다. 지정 안 해줘도 되는 값이지만, 지정하지 않고, random 하게 설정하게 된다면 가끔 한 번만 돌기 때문에 validation scores가 향상되지 않을 수도 있다고 합니다. 따라서 5가 가장 적절하다고 합니다. 또한 early_stopping_rounds를 설정하게 된다면, eval_set 매개변수도 함께 설정해줘야 합니다.
my_model = XGBRegressor()
my_model = XGBRegressor(n_estimators=500, max_depth=20, enable_categorical=True, verbosity=2)
my_model.fit(X_train, y_train, early_stopping_rounds=5, eval_set=[(X_valid, y_valid)], vervose=False)
미리 train 데이터와 8:2로 분리해 뒀던 valid 데이터를 MAE 점수를 가지고 모델의 성능을 확인해 보겠습니다.
predictions_xgboost = my_model.predict(X_valid)
# Calculate MAE
mae_xgboost = mean_absolute_error(y_valid, predictions_xgboost)
print(mae_xgboost)
이렇게 피팅한 모델을 가지고 y값을 모르는 데이터를 예측해 보겠습니다.
X_test[cat_attribs] = X_test[cat_attribs].astype('category')
preds_test = my_model.predict(X_test)
예측 결과인 preds_test를 Kaggle competition 제출 규칙에 맞춰서 .csv를 제작합니다. 규칙은 데이터 링크에서 sample_submission.csv 파일을 통해 확인할 수 있습니다.
n_preds_test = (preds_test > 0.5).astype(bool)
# Save test predictions to file
output = pd.DataFrame({'PassengerId': X_test.PassengerId,
'Transported': n_preds_test})
output.to_csv('submission.csv', index=False)
output.info()
제작한 .csv를 제출하고 싶다면, 우측 하단에 화살표를 열어서 오른쪽 사이드바를 열어줍니다.(열려있을 수도 있습니다.) 중간 위치에 Submit to competion이 있고, Submit 버튼을 눌러 제출할 수 있습니다.
제출 후에는 Competition의 Submissions 탭에서 예측 결과를 확인할 수 있습니다. 모델의 매개변수들을 계속 조절하면서 예측 성능을 향상하면 되겠습니다.
출처:
https://www.kaggle.com/competitions/spaceship-titanic
https://www.kaggle.com/code/alexisbcook/xgboost
XGBoost
Explore and run machine learning code with Kaggle Notebooks | Using data from multiple data sources
www.kaggle.com
J Lee