Python/데이터분석 실습

[DACON_101] Lv.2 결측치 보간법과 랜덤포레스트로 따릉이 데이터 예측하기

dori_0 2022. 2. 2. 23:34

https://dacon.io/competitions/open/235698/overview/description

▶ [ Lv.2 결측치 보간법과 랜덤포레스트로 따릉이 데이터 예측하기 ] 를 공부했습니다.


 

EDA _ 탐색적 자료 분석

이전 게시글 Lv1과 데이터가 같으므로 이 단계에서 행, 열 개수 확인/ 데이터 확인은 생략하겠습니다!

 

1. 라이브러리, 파일 불러오기

데이터분석을 하기 위해 pandas 라이브러리와 파일을 불러오기

import pandas as pd

train = pd.read_csv('C:/data/train.csv')
test = pd.read_csv('C:/data/test.csv')
 

 

전처리

1. 결측치 삭제, 대체

 

(방법 1) 결측치를 평균값으로 대체

 

Lv1에서는 결측치를 0으로 대체했었는데 이번엔 각 피쳐의 평균값으로 대체해보자

먼저, train에서 결측치가 있는 피쳐를 살펴보자

train.isnull().sum()
 

hour_bef_temperature, hour_bef_precipitation, hour_bef_windspeed, hour_bef_humidity, hour_bef_visibility, hour_bef_ozone, hour_bef_pm10, hour_bef_pm2.5 피쳐들에 결측치가 존재

 

fillna()를 이용해 train의 결측치를 각 피쳐의 평균값으로 대체

train.fillna({'hour_bef_temperature':int(train['hour_bef_temperature'].mean())}, inplace=True)
train.fillna({'hour_bef_precipitation':int(train['hour_bef_precipitation'].mean())}, inplace=True)
train.fillna({'hour_bef_windspeed':int(train['hour_bef_windspeed'].mean())}, inplace=True)
train.fillna({'hour_bef_humidity':int(train['hour_bef_humidity'].mean())}, inplace=True)
train.fillna({'hour_bef_visibility':int(train['hour_bef_visibility'].mean())}, inplace=True)
train.fillna({'hour_bef_ozone':int(train['hour_bef_ozone'].mean())}, inplace=True)
train.fillna({'hour_bef_pm10':int(train['hour_bef_pm10'].mean())}, inplace=True)
train.fillna({'hour_bef_pm2.5':int(train['hour_bef_pm2.5'].mean())}, inplace=True)
 

같은 방법으로 test의 결측치가 있는 피쳐를 찾아 평균값으로 대체해보자

test.isnull().sum()

test.fillna({'hour_bef_temperature':int(test['hour_bef_temperature'].mean())}, inplace=True)
test.fillna({'hour_bef_precipitation':int(test['hour_bef_precipitation'].mean())}, inplace=True)
test.fillna({'hour_bef_windspeed':int(test['hour_bef_windspeed'].mean())}, inplace=True)
test.fillna({'hour_bef_humidity':int(test['hour_bef_humidity'].mean())}, inplace=True)
test.fillna({'hour_bef_visibility':int(test['hour_bef_visibility'].mean())}, inplace=True)
test.fillna({'hour_bef_ozone':int(test['hour_bef_ozone'].mean())}, inplace=True)
test.fillna({'hour_bef_pm10':int(test['hour_bef_pm10'].mean())}, inplace=True)
test.fillna({'hour_bef_pm2.5':int(test['hour_bef_pm2.5'].mean())}, inplace=True)
 

대체 후 다시 확인해보니 평균값으로 잘 대체된 것을 알 수 있다.

train.isnull().sum()
test.isnull().sum()
 

 

 

(방법 2) 보간법을 사용해 결측치 대체

피쳐의 정보성을 강조하기 위해 보간법을 사용해 결측치를 대체해보기

 

먼저, train에서 결측치가 있는 피쳐를 살펴보자

train.isnull().sum()

train.interpolate(inplace = True)
train.isnull().sum()

interpolate()를 이용해 결측치를 보간법으로 대체 후 확인해보니 잘 대체된 것이 확인된다.

 

같은 방법으로 test의 결측치 역시 보간법으로 대체 후 확인해보니 잘 대체된 것이 확인된다.

test.isnull().sum()

test.interpolate(inplace = True)
test.isnull().sum()
 

 

 모델링

※ 랜덤포레스트란?

  • 여러 개의 의사결정나무를 만들어서 이들의 평균으로 예측의 성능을 높이는 방법
  • 이러한 기법을 앙상블 기법이라고 함
  • 주어진 하나의 데이터로부터 여러 개의 랜덤 데이터셋을 추출해, 각 데이터셋을 통해 여러 모델을 만들 수 있음

 

1. 랜덤포레스트 선언

sklearn.ensemble에서 RandomForestRegressor 불러오기

from sklearn.ensemble import RandomForestRegressor
model = RandomForestRegressor()
 

 

2. 랜덤포레스트를 평가척도에 맞게 학습

따릉이 대회의 평가지표는 MSE이므로 모델을 선언할 때 criterion='mse' 옵션으로 구현

count 피쳐를 제외한 X_train, Y_train df를 생성

X_train = train.drop(['count'], axis = 1)
Y_train = train['count']

model = RandomForestRegressor(criterion = 'mse')
model.fit(X_train, Y_train)
 

 

 튜닝

1. 랜덤포레스트 변수 중요도 확인

모델 학습 후 feature_importances_attribute로 변수의 중요도 파악

변수의 중요도란, 예측변수를 결정할 때 각 피쳐가 얼마나 중요한 역할을 하는지에 대한 척도

변수의 중요도가 낮으면 해당 피쳐를 제거하는 것이 모델의 성능을 높일 수 있음!

model.feature_importances_
 

 

2. 변수 중요도가 낮은 피쳐 제거

변수 중요도가 낮은 피쳐를 하나씩 제거하며 모델을 새로 훈련 할 수 있음

 

위의 결과에서 id, hour_bef_precipitation, hour_bef_pm2.5 피쳐는 예측에 의미가 없는 피쳐로 보인다.

따라서 하나씩 drop 하며 X_train들을 만들어보고, 각 train에 따른 test 셋들을 만들어보자

# X_train 에서 drop 할 피쳐의 경우에 수 대로 3개의 X_train 을 생성
# 각 train 에 따라 동일하게 피쳐를 drop 한 test 셋들을 생성

X_train_1 = train.drop(['id', 'count'], axis=1)
X_train_2 = train.drop(['id', 'count', 'hour_bef_precipitation'], axis=1)
X_train_3 = train.drop(['id', 'count', 'hour_bef_precipitation', 'hour_bef_pm2.5'], axis=1)

test_1 = test.drop(['id'], axis=1)
test_2 = test.drop(['id', 'hour_bef_precipitation'], axis=1)
test_3 = test.drop(['id', 'hour_bef_precipitation', 'hour_bef_pm2.5'], axis=1)
 

각 X_train들에 대해 모델 훈련을 시키자

model_input_1 = RandomForestRegressor(criterion = 'mse')
model_input_1.fit(X_train_1, Y_train)
model_input_2 = RandomForestRegressor(criterion = 'mse')
model_input_2.fit(X_train_2, Y_train)
model_input_3 = RandomForestRegressor(criterion = 'mse')
model_input_3.fit(X_train_3, Y_train)
 

그 후, 각 모델들로 test 셋들을 예측하자

pred_1 = model_input_1.predict(test_1)
pred_2 = model_input_2.predict(test_2)
pred_3 = model_input_3.predict(test_3)
 

이 결과들을 submisson 파일로 저장하면

submission_1 = pd.read_csv('C:/data/submission.csv')
submission_2 = pd.read_csv('C:/data/submission.csv')
submission_3 = pd.read_csv('C:/data/submission.csv')

submission_1['count'] = pred_1
submission_2['count'] = pred_2
submission_3['count'] = pred_3

submission_1.to_csv('sub_1.csv',index = False)
submission_2.to_csv('sub_2.csv',index = False)
submission_3.to_csv('sub_3.csv',index = False)
 

이렇게 저장이 된다!


※ 하이퍼파라미터 튜닝이란?

 

GridSearchCV 모듈로 하이퍼파라미터 튜닝을 구현해보자!

 

1. EDA와 전처리

import pandas as pd


train = pd.read_csv('C:/data/train.csv')
test = pd.read_csv('C:/data/test.csv')


from sklearn.ensemble import RandomForestRegressor


train.interpolate(inplace = True)
test.fillna(0, inplace=True) # 결측치 0으로 채워주기


X_train = train.drop(['id', 'count', 'hour_bef_precipitation', 'hour_bef_pm2.5'], axis=1)
Y_train = train['count']
test = test.drop(['id', 'hour_bef_precipitation', 'hour_bef_pm2.5'], axis=1)
 

앞 과정에서 파악한 변수 중요도가 낮은 피쳐를 제거해 X_train, Y_train, test를 만들었다.

 

 

2. 하이퍼파라미터 튜닝 구현

from sklearn.model_selection import GridSearchCV

model = RandomForestRegressor(criterion = 'mse', random_state = 2020)

params = {'n_estimators':[200, 300, 500],
         'max_features':[5, 6, 8],
         'min_samples_leaf':[1, 3, 5]}

greedy_CV = GridSearchCV(model, param_grid = params, cv=3, n_jobs = -1)
greedy_CV.fit(X_train, Y_train)
 

그 후, 각 모델로 test를 예측하자

pred = greedy_CV.predict(test)
pred
 

이 결과들을 submisson 파일로 저장하면

submission = pd.read_csv('C:/data/submission.csv')

import numpy as np
submission['count'] = np.round(pred, 2)

submission.to_csv('sub_np.csv', index=False)
 
 

 

이렇게 저장된다!