서울시 따릉이 자전거 이용 예측 AI모델 (Bike Sharing Demand)

서울시 따릉이 자전거 이용 예측 AI모델 (Bike Sharing Demand)

Lv1. 의사결정회귀나무로 따릉이 데이터 예측하기

https://dacon.io/competitions/open/235576/overview

[데이터]

2017년 4월 1일부터 - 5월 31일까지 시간별 따릉이 대여수와 기상상황

id : 날짜와 시간별 id

hour_bef_temperature : 1시간 전 기온

hour_bef_precipitation : 1시간 전 비 정보, 비가 오지 않았으면 0, 비가 오면 1

hour_bef_windspeed : 1시간 전 풍속(평균)

hour_bef_humidity : 1시간 전 습도

hour_bef_visibility : 1시간 전 시정(視程), 시계(視界)(특정 기상 상태에 따른 가시성을 의미)

hour_bef_ozone : 1시간 전 오존

hour_bef_pm10 : 1시간 전 미세먼지(머리카락 굵기의 1/5에서 1/7 크기의 미세먼지)

hour_bef_pm2.5 : 1시간 전 미세먼지(머리카락 굵기의 1/20에서 1/30 크기의 미세먼지)

count : 시간에 따른 따릉이 대여 수

[목표]

각 날짜의 1시간 전의 기상상황으로 1시간 후의 따릉이 대여수를 예측하기

[평가지표]

RMSE

[과정 요약]

1. EDA

2. 전처리 : 보간법 or 시간대별 평균치

3. 모델링 : 의사결정나무. 변수 중요도가 낮은 컬럼을 제외해가며 RMSE 체크. 하이퍼파라미터 값을 수정해가며 튜닝하기

1. 파일 불러오기 ~ EDA

train.head()

train.shape

train.info()

train.discribe()

train.groupby('hour').mean()['count'].plot()

히트맵 등

import pandas as pd from sklearn.ensemble import RandomForestRegressor train = pd.read_csv(r'./data/train.csv') test = pd.read_csv(r'./data/test.csv') submission = pd.read_csv(r'./data/submission.csv') # 답안지 train.info() # 결측치 확인 # 변수 간 상관관계 확인 import seaborn as sns plt.figure(figsize=(10,10)) sns.heatmap(train.corr(), annot=True, fmt='.2f') # annot_kws={'size':10, }, cmap = 'rainbow' train.isna().sum() train[train['hour_bef_temperature'].isna()] # 결측치 위치 확인 # 0시, 18시인데 두 시간대의 온도는 매우 다를 것이므로 온도 컬럼 전체의 중앙값/평균값 같은 걸로 대체하는건 무리가 있다고 판단.

2. 전처리

결측치를 대체하기 위해 여기서 사용한 방법은

1) 보간법

2) 시간별 평균값을 이용해서 결측치를 대체 - 컬럼마다 시간별 평균값을 체크해야한다는 점에서 보간법보다 시간이 더 걸림

# 보간법 train.interpolate(inplace=True) test.interpolate(inplace=True)

# 시간별 평균값 확인해서 결측값을 메꾸기 train.groupby('hour')['hour_bef_temperature'].mean() train['hour_bef_temperature'].fillna({934:14.788136, 1035:20.926667}, inplace=True) # 저장하기 위해서 inplace 옵션 True # 마찬가지로 test 결측치 처리. 이 때 결측값을 대체할 값은 train에서 가져온다는 점 주의

3. 모델링

from sklearn.ensemble import RandomForestRegressor model = RandomForestRegressor(criterion = 'mse') # 따릉이 대회의 평가지표는 RMSE. RMSE는 MSE 평가지표에 루트를 씌운 것이므로 MSE를 평가척도로 정함. X_train = train.drop(['count'], axis=1) Y_train = train['count'] model.fit(X_train, Y_train) # 모델 학습

변수의 중요도를 파악해서, 낮은 변수부터 하나씩 제거해가며 여러 모델을 테스트 해본다.

model.feature_importances_ # 변수의 중요도 파악 # 첫번째 모델 = id, count 컬럼 제외 X_train_1 = train.drop(['id','count'], axis=1) test_1 = test.drop(['id'], axis=1) model_1 = RandomForestRegressor(criterion = 'mse') model_1.fit(X_train_1, Y_train) ypread_1 = model_1.predict(test_1) submission_1 = pd.read_csv(r'./data/submission.csv') # 답안지 submission_1['count'] = ypread_1 submission_1.to_csv(r'./submission_1.csv', index=False) # 두번째 모델 = id, count, hour_bef_precipitation 제외 X_train_2 = train.drop(['id','count','hour_bef_precipitation'], axis=1) test_2 = test.drop(['id','hour_bef_precipitation'], axis=1) model_2 = RandomForestRegressor(criterion = 'mse') model_2.fit(X_train_2, Y_train) ypread_2 = model_2.predict(test_2) submission_2 = pd.read_csv(r'./data/submission.csv') # 답안지 submission_2['count'] = ypread_2 submission_2.to_csv(r'./submission_2.csv', index=False)

이런 식으로 네가지 모델을 돌려봤는데,

id, count, hour_bef_precipitation, hour_bef_pm2.5 변수를 제거한 모델3이 RMSE 46.87 정도로 가장 낮게 나왔다.

다음으로 하이퍼파라미터 튜닝.

이를 통해 모델의 과적합을 방지하고 스코어를 올린다.

Scikit-learn 패키지의 GridSearchCV 이용

GridSearch는 완전 탐색(Exhaustive Search)을 사용해서 가능한 모든 조합 중 가장 우수한 조합을 찾아줌(시간이 오래 걸린다는 단점)

1. n_estimators=100 학습시킬 의사결정나무 개수(이를 종합해서 최종값 산출하게 됨)

2. max_depth=None 뿌리 노드로부터 최대로 내려갈 수 있는 나무의 깊이. 과대적합 방지용.

3. n_jobs=None 사용하고자 하는 CPU 개수. 많이 쓸수록 빠름. 모두 활용하려면 -1

4. min_samples_leaf leaf 노드에서 필요한 최소한의 샘플 수. 너무 적으면 과적합이 일어날 수 있다

5. criterion 노드 분리기준. gini( / entropy(데이터 혼잡도)

6. splitter 노드 분리 방법. random / best

from sklearn.model_selection import GridSearchCV model = RandomForestRegressor(criterion = 'mse', random_state=0) parameters = {'n_estimators': [200, 300, 500], 'max_features': [5, 6, 7, 8], 'min_samples_leaf': [1, 3, 5]} greedy_CV = GridSearchCV(model, param_grid=parameters, cv = 3, n_jobs = -1) greedy_CV.fit(X_train, Y_train) greedy_CV.best_params_ greedy_CV_pred = greedy_CV.predict(test) submission['count'] = greedy_CV_pred submission.to_csv(r'./submission_greedyCV.csv', index=False)

max_features : 8, min_samples_leaf : 3, n_estimators : 300 일 때

앞서 테스트했던 모델3보다 더 낮은 RMSE 기록.

더 공부해서 디벨롭하기 !

https://www.kaggle.com/c/bike-sharing-demand/data

https://throwexception.tistory.com/1078

https://diane-space.tistory.com/67

https://dailyheumsi.tistory.com/95

https://continuous-development.tistory.com/173

https://github.com/BaekKyunShin/Kaggle/blob/master/Bike_Sharing_Demand/Bike%20Sharing%20Demand%20by%20Ensemble.ipynb

from http://hjryu09.tistory.com/15 by ccl(A) rewrite - 2021-12-20 18:00:24