본문 바로가기
AI SCHOOL/TIL

[DAY 55] 캐글 경진대회 상위 3% 경험하기 - 수요 예측(회귀), 부스팅 모델, GridSearchCV

2023. 3. 15.

Kaggle Competition : Bike Sharing Demand를 경험했다. 자전거 수요를 회귀 모델을 사용해 예측하고 제출하여 점수를 확인했다.

Gradient Boosting 모델을 사용했으며 GridSearchCV를 통해 최적의 하이퍼 파라미터를 탐색했다.

데이터 준비

competition page에서 train.csv, test.csv, sampleSubmission.csv를 다운로드했다. 각각 학습, 예측, 제출에 사용할 파일이다.
그 후 train.csv와 test.csv를 로드하여 각각 변수에 저장했다.

print(train.shape)
train.head()

train 데이터의 shape와 처음 5개 행 확인

train

 

print(test.shape)
test.head()

test 데이터의 shape와 처음 5개 행 확인

test

train 데이터가 test 데이터보다 열 수가 많은데, 이는 train에 예측해야 할 값이 포함되어 있기 때문이다.

train["datetime"] = pd.to_datetime(train["datetime"])
train["year"] = train["datetime"].dt.year
train["hour"] = train["datetime"].dt.hour
train["dayofweek"] = train["datetime"].dt.dayofweek

test["datetime"] = pd.to_datetime(test["datetime"])
test["year"] = test["datetime"].dt.year
test["hour"] = test["datetime"].dt.hour
test["dayofweek"] = test["datetime"].dt.dayofweek

train과 test 데이터에 예측과 학습에 사용할 연도, 시간, 요일 변수를 추가했다.

EDA

예측해야 할 값은 count 값이다. train['count']를 히스토그램과 kdeplot을 그려 확인하면 아래와 같다.

kdecount

한쪽으로 매우 편향된 분포를 확인할 수 있다. 이런 경우 log를 사용하는 것이 좋다.

# count에 log를 취해준다
train['count_log1p'] = np.log1p(train['count'])
train[['count', 'count_log1p']].hist(bins=50, figsize=(12,4))

count와 numpy의 함수를 통해 로그를 취한 count_log1p를 비교해 보자.

log

육안으로도 개선된 것이 확인된다.
로그를 적용하면 상대적으로 큰 값에 대한 스케일을 줄여서 스케일 차이가 많이 나는 경우 평가 성능이 좋아질 수 있다.

logfunc
log


로그를 적용하여 모델을 학습시키고 예측값을 얻게 되면, 반드시 다시 로그 적용을 복원해야 한다.
이때 numpy의 exp 함수를 사용한다.

train['count_expm1'] = np.exp(train['count_log1p']) - 1
train[['count', 'count_log1p', 'count_expml']].hist(bins=50, figsize=(10, 4))

원래 값, 로그 적용한 값, 적용한 로그를 복원한 값에 대해 히스토그램으로 확인한다.

hist2

원래 값과 로그 적용 후 복원한 값이 같아 보인다.

describe

기술통계 값을 확인한 결과 정확히 복원되었다.
이제 학습, 예측 데이터를 준비하고 log와 exp를 활용해 본다.

학습에 사용할 데이터셋(X_train, y_train),  예측에 사용할 데이터셋 (X_test) 만들기

# 예측 target
label_name = 'count'
# 사용할 컬럼
feature_names = ['season', 'holiday', 'workingday', 'weather', 'temp',
                 'atemp', 'humidity', 'windspeed', 'year', 'hour', 'dayofweek']

먼저 학습과 예측에 사용할 컬럼을 정하고 target인 컬럼명 "count"는 label_name에 지정했다.

X_train = train[feature_names]
print(X_train.shape)
X_train.head(2)

학습에 사용할 데이터셋의 shape과 처음 2개 행 확인

xtrain

 

y_train = np.log1p(train[label_name])  # 로그 적용
y_train

학습에 사용할 X_train의 정답 값에 해당하는 데이터셋 확인

ytrain

y_train은 X_train과 동일한 개수인 Series다.

X_test = test[feature_names]
print(X_test.shape)
X_test.head(2)

예측에 사용할 데이터셋의 shape과 처음 2개 행 확인

xtest

X_test는 X_train에 비해 행 수가 적으며 컬럼 수는 같다.

머신러닝 모델을 활용한 학습과 예측

회귀 문제에 성능이 좋은 부스팅 모델을 사용한다.

from sklearn.ensemble import GradientBoostingRegressor
model = GradientBoostingRegressor(random_state=42)

GradientBoostingRegressor 모델을 생성했다.

GridSearchCV를 통해 최적의 하이퍼 파라미터를 찾는다.

parameters = {'n_estimators': (200, 300, 400),
              'learning_rate': (0.05, 0.1, 0.2)}
              
from sklearn.model_selection import GridSearchCV

reg = GridSearchCV(model, parameters, cv=3, n_jobs=-1, verbose=2)
reg.fit(X_train, y_train)  # 3*3개의 조합, cross validation 조각 3개
reg.best_estimator_

 

Fitting 3 folds for each of 9 candidates, totalling 27 fits를 통해 아래와 같은 best estimator를 얻었다.

best


이렇게 구한 모델에 X_train, y_train을 학습시키고 X_test에 대한 예측값을 얻는다.

y_pred = reg.best_estimator_.fit(X_train, y_train).predict(X_test)
y_pred = np.expm1(y_pred)
y_pred  # 로그를 적용하여 학습했기 때문에 예측값은 로그 적용을 복원

학습시 로그를 적용한 y_train 값을 사용했기 때문에 역으로 예측값에 exp를 적용했다.

Kaggle에 제출 및 점수 확인

df_submit = pd.read_csv('sampleSubmission.csv')
df_submit['count'] = y_pred
df_submit

답안지 양식을 로드한 후 예측한 값 y_pred를 입력한다.

predict

날짜,시간대별 예측값이 count 컬럼에 잘 입력되었다.

이제 캐글에 제출하기 위해 csv파일로 저장한 후

submisson
latesubmisson

실제로 제출해서

complete
제출 결과

채점된 score를 확인한 결과 0.37359라는 결과를 받았다.

leaderboard
leaderboard

당시의 Competition 결과를 Leaderboard에서 보니, 91위에 해당하는 점수인 것을 확인할 수 있다.

이렇게 부스팅 모델과 그리드서치를 이용하여 캐글 자전거 수요 예측대회에서 전체 3242팀 중 91위(상위 2.8%)에 해당하는 성적을 받아 보는 경험을 했다. 재미있었다.

반응형

댓글