본문 바로가기
AI SCHOOL/TIL

[DAY 58] 머신러닝으로 자전거 수요 예측 - GradientBoostingRegressor, RandomizedSearchCV

2023. 3. 20.

회귀 문제에 성능이 좋은 부스팅 모델을 사용하여 자전거 수요를 예측했다.

RandomizedSearchCV를 통해 최적의 하이퍼파라미터를 탐색하고 GridSearchCV와 비교했다.

데이터 준비

캐글 페이지에서 학습, 예측, 제출에 사용할 파일 train.csv, test.csv, sampleSubmission.csv를 다운로드했다. 그 후 pandas를 통해 train과 test 데이터를 로드하여 형태를 확인했다.

print(train.shape)
train.head()

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

trained

 

print(test.shape)
test.head()

test도 마찬가지로 확인

tested

casual, registered, count는 자전거 수요를 의미한다.
test 데이터를 활용하여 예측해야하는 값이기 때문에 test에는 해당 변수가 없다.

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

datetime 변수를 통해 파생변수 year, hour, dayofweek을 생성했다.

학습과 예측에 사용할 데이터셋 정의 및 확인

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

예측할 count 변수를 label_name에 대입해주고, 학습과 예측에 사용할 컬럼명 11개의 리스트를 feature_names에 담는다.

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

학습에 사용할 데이터셋 X_train 정의 및 확인

xtrain

 

# 상대적 큰 값의 스케일을 줄여 성능을 높이기 위해 로그 적용
y_train = np.log1p(train[label_name])
y_train

X_train의 정답 값에 해당하는 y_train 정의 및 확인

ytrain

y_train은 X_train과 데이터 수가 10886개로 같다.
로그를 적용했으므로 예측 후 다시 복원하는 과정이 필요하다.

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

예측에 사용할 데이터셋 X_test 정의 및 확인

xtest

X_test는 X_train과 같은 변수로 이루어지며 행 수는 다를 수 있다. X_test의 행 수가 적은 것이 일반적이다.

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

부스팅 알고리즘을 적용한 앙상블 모델을 사용한다.

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

GradientBoostingRegressor 회귀모델을 생성했다.

RandomizedSearchCV : 최적의 하이퍼 파라미터 탐색
그리드 서치는 지정된 구간에 대한 값에 대해 탐색하는데, 지정된 구간 외에 최적 값이 있는 경우 찾지 못 하는 단점이 있다. 이런 단점을 보완하여 랜덤한 값들을 지정하여 성능을 평가하고 그 중 가장 좋은 성능을 내는 파라미터를 찾는 방법이 랜덤 서치다. 구간을 점점 좁혀가며 성능을 높일 수 있다.

gridrandom
그리드서치와 랜덤서치 비교

 

from sklearn.model_selection import RandomizedSearchCV
param_distributions = {'n_estimators':np.random.randint(100, 300, 20),
                       'learning_rate':np.random.uniform(low=0.05, high=0.3, size=20)
                      }

reg = RandomizedSearchCV(model,
                         param_distributions=param_distributions,
                         n_iter=20, n_jobs=-1,
                         scoring='neg_root_mean_squared_error',
                         cv=3, verbose=1, random_state=42)
reg.fit(X_train, y_train)

param_distributions에 np.random을 사용해서 n_estimators와 learning_rate를 지정했다.
또한 해당 캐글 대회의 평가 기준은 RMSLE인데 현재 target에 이미 로그가 취해진 상태기 때문에 RMSE를 scoring으로 지정한 것이다.

Fitting 3 folds for each of 20 candidates, totalling 60 fits를 통해 최적의 하이퍼파라미터가 결정되었다.

reg.best_estimator_

best_estimator_를 확인하면 아래와 같다.

bestest

param_distributions를 랜덤하게 지정했기 때문에 코드를 실행할 때마다 결과가 달라질 수 있다.

result = pd.DataFrame(reg.cv_results_)
result.sort_values('rank_test_score')

1위부터 20위까지의 결과를 데이터프레임으로 만들어 랭크순으로 정렬하면 아래와 같은 결과를 볼 수 있다.

best20

rank_test_score 1위가 best_estimator와 같다.

RandomizedSearchCV의 결과로 구한 모델에 X_train과 y_train을 학습시킨 후 X_test에 대한 예측값 y_pred를 얻는다.

y_pred = (reg.best_estimator_).fit(X_train, y_train).predict(X_test)
y_pred = np.expm1(y_pred)

log를 적용하여 학습했기 때문에 예측값에 exponential을 적용하여 복원해준다.

Kaggle에 제출, score 확인

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

제출 파일 양식을 로드한 후 예측한 결과인 y_pred를 입력한다.

ypred

예측값이 날짜, 시간대별 count에 잘 입력된 것을 확인할 수 있다.
X_test의 수와 같은 이 6493행의 데이터프레임을 제출하면 된다.

df_submit.to_csv('submit_randomsearch.csv', index=False)

to_csv를 통해 csv파일로 저장한 후 Kaggle에 제출한 결과

submited

0.37376이라는 점수를 받았다. GridSearchCV를 사용했을 때는 0.37359를 받았는데 아주 근소하게 높아졌다.
랜덤서치를 시간을 들여 더 세밀하게 사용한다면 더욱 좋은 결과를 얻을 수 있을 것이다.

반응형

댓글