본문 바로가기

Data Science/ML & DL

Lv2. 결측치 보간법과 랜덤포레스트로 따릉이 데이터 예측하기

 

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

[DACON_101]  Lv.2 결측치 보간법과 랜덤포레스트로 따릉이 데이터 예측하기 를 공부하고 정리한 내용


서울시 따릉이 대여량 예측 경진대회

주어진 데이터를 바탕으로 따릉이 대여량을 예측하는 대회

링크 : https://dacon.io/competitions/open/235576/mysubmission

분류 : 정형, 알고리즘, 초급

data : 서울시 마포구의 날짜별, 시간별 기상상황과 따릉이 대여 수 데이터

  • id 고유 id
  • hour 시간
  • temperature 기온
  • precipitation 비가 오지 않았으면 0, 비가 오면 1
  • windspeed 풍속(평균)
  • humidity 습도
  • visibility 시정(視程), 시계(視界)(특정 기상 상태에 따른 가시성을 의미)
  • ozone 오존
  • pm10 미세먼지(머리카락 굵기의 1/5에서 1/7 크기의 미세먼지)
  • pm2.5 미세먼지(머리카락 굵기의 1/20에서 1/30 크기의 미세먼지)
  • count 시간에 따른 따릉이 대여 수

 

 

 

데이터 다운로드

# 데이터 다운로드 링크로 데이터를 코랩에 불러옵니다.

!wget 'https://bit.ly/3gLj0Q6'

import zipfile
with zipfile.ZipFile('3gLj0Q6', 'r') as existing_zip:
    existing_zip.extractall('data')

 

 

 

🚩1단계 : EDA

  1. 라이브러리/데이터 불러오기
  2. shape
  3. head
  4. isnull

 

 

1. 데이터 불러오기
data폴더에 있는 test.csv, train.csv 불러오기

import pandas as pd

train = pd.reas_csv('data/train.csv')
test = pd.read_csv('data.csv')
  1. 행 열 갯수 관찰하기
    train.shape
    test.shape
    (1459, 11)
    (715, 10)
  1. 데이터 확인하기
    head() 메소드로 상위 데이터를 확인한다,
    train.head()
    test.head()

 

 

🚩 2단계 : 전처리

 

1. 결측치 보간법 - inerpolate()

 

 

결측치 확인하기- isnull() /결측치 보간법 - inerpolate()
따릉이 데이터 - 피쳐들이 데이터의 순서가 시간순서(시계열 데이터)이므로 직전시간과 직후시간의 평균으로 보간하는 것은 합리적

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

train.interpolate(inplace = True) test.interpolate(inplace = True)

 

결측치가 잘 채워졌는지 확인

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

 

🚩 3단계 : 모델링

 

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

※ 랜덤포레스트란?

🔗 https://wooono.tistory.com/115

앙상블(Ensemble) 학습 방법 중 하나로, 여러 개의 결정 트리(Decision Tree)를 조합하여 더 강력한 분류 모델을 구축하는 방법.
각 의사결정나무의 예측 결과를 다수결방식으로 조합하여 최종 예측 결과를 결정함
전체 특징 중 일부 특징을 무작위로 선택하여 가장 결과를 잘 예측할 수 있는 하나의 트리를 구성
분류 문제에서 불순도에 대한 지표로써 지니 지수(Gini index) 또는 엔트로피(entropy)가 사용되고,

회귀 문제에서는 평균제곱오차(Mean Square Error)가 불순도 지표로 사용된다.

 

장점
랜덤 포레스트는 과적합(Overfitting)을 줄이고 예측 성능을 향상시키는데 효과적이며, 결측치를 다루기가 쉽다.
대용량 데이터 처리에 효과적이며 분류 모델에서 상대적으로 중요한 변수를 선정할 수 있다.

파라미터
랜점 포레스트 안의 결정트리 개수(n_estimators = default 10)는 클수록 결정 트리가 많아서 좋으나, 메모리와 훈련시간이 길어진다.

 

 

(1)model.feature_importances_ 으로 변수 중요도 확인 후 column과 대응

index = train.columns
A = model.feature_importances_ 

result = {}
for idx,a in zip(index,A):
  result[idx] = a

print(result)

 

결과를 df형태로 확인하고, 중요도 기준 오름차순 정렬한다.
.items (key:value 튜플반환) ->list()

df = pd.DataFrame(list(result.items()), columns =['key', 'value'])
df['value'].astype(float)

df.sort_values(by = 'value')

 

 

(2) 중요도 낮은 변수 제거 (drop()) ⭐⭐
변수 중요도가 낮은 피쳐를 파악하고 나면 차례대로 피쳐를 제거해가면서 모델을 새로 훈련하기
id, count를 제거한 X_train 데이터에서 hour_bef_windspeedhour_bef_pm2.5 피쳐에 관하여도 추가로 drop 을 수행하기

  • X_train 에서 drop 할 피쳐의 경우에 수 대로 3개의 X_train 을 생성하세요.
X_train_1 = train.drop(['count','id'], axis=1)
X_train_2 = train.drop(['count','id','hour_bef_windspeed'], axis=1)
X_train_3 = train.drop(['count','id','hour_bef_windspeed', 'hour_bef_pm2.5'], axis=1)
  • 각 train 에 따라 동일하게 피쳐를 drop 한 test 셋들을 생성하세요.
test_1 = test.drop(['id'], axis=1) 
test_2 = test.drop(['id','hour_bef_windspeed'], axis=1) 
test_3 = test.drop(['id','hour_bef_windspeed', 'hour_bef_pm2.5'], axis=1)

 

 

(3) 랜덤포레스트를 평가척도에 맞게 학습

랜덤포레스트는 critician 옵션으로 어떤 평가 척도 기준으로 훈련할 지 정할 수 있음

따릉이 대회는 RMSE가 평가척도이므로, mse를 평가척도로 학습, default critician이 mse이므로 따로 설정할 필요 없음
또한 랜덤포레스트(회귀)에서 불순도 지표 MSE

  • 각 X_train에 대해 모델 훈련을 해주세요.
model_ver1 = RandomForestRegressor() 
model_ver1.fit(X_train_1, y_train)

model_ver2 = RandomForestRegressor()
model_ver2.fit(X_train_2, y_train)

model_ver3 = RandomForestRegressor()
model_ver3.fit(X_train_3, y_train)
  • 각 모델로 test 셋들을 예측해주세요
y_pred_1 = model_ver1.predict(test_1)
y_pred_2 = model_ver2.predict(test_2)
y_pred_3 = model_ver3.predict(test_3)
  • 각 결과들을 submission 파일로 저장해주세요.
submission_1 = pd.read_csv('data/submission.csv')
submission_2 = pd.read_csv('data/submission.csv')
submission_3 = pd.read_csv('data/submission.csv')

submission_1['count'] = y_pred_1
submission_2['count'] = y_pred_2
submission_3['count'] = y_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)

 

결과확인
sub_1.csv

 

 

sub_2.csv

sub_3.csv

 

 

 

 

2. GridSearchCV 모듈로 완전탐색 하이퍼파라미터 튜닝을 구현

python 파이썬 하이퍼파라미터 튜닝 / GridSearch 개념

의사결정나무의 정지규칙(stopping criteria) 중 4가지 정지규칙을 소개한다. 

아래와 같은 정지규칙을 종합적으로 고려해 최적의 조건값을 설정할 수 있으며 이를 하이퍼파라미터 튜닝라고 한다.

 

1. 최대깊이 (max_depth)

- 최대로 내려갈 수 있는 depth, 뿌리 노드로 부터 내려갈 수 있는 깊이를 지정하여 작을 수록 트리가 작아짐

2. 최소 노드크기(min_samples_split)

- 노드를 분할하기 위한 데이터 수, 해당 노드에 이 값보다 적은 확률변수 수가 있다면 stop, 작을수록 트리는 커짐

3. 최소 향상도(min_impurity_decrease)

- 노드를 분할하기 위한 최소 향상도, 향상도가 설정값 이하라면 더 이상 분할하지않음. 작을수록 트리가 커짐

4. 비용복잡도(Cost-complexity)

- 트리가 커지는 것에 대해 패널티 계수를 설정해서 불순도와 트리가 커지는 것에 대해 복잡도를 계산

 

하이퍼 파라미터 튜닝에는 다양한 방법론이 있음. 

GridSearch는 완전 탐색(Exhaustive Search)를 사용해 가능한 모든 조합 중 가장 우수한 조합을 찾아냄

완전 탐색이므로 Best 조합을 찾을 때까지 시간이 오래걸린다는 단점이 있음

 

[  GridSearchCV 실습   ]

 

(1)  scikit-learn 라이브러리에서 GridSearchCV 클래스를 가져오기

모델의 하이퍼파라미터 튜닝을 수행해 최적의 파라미터 조합을 찾음

from sklearn.model_selection import GridSearchCV

 

 

 

(2) GridSearch 중 탐색하려는 하이퍼 파라미터와 그들의 가능한 값을 정함

  • n_estimators: 숲의 결정 트리 개수
  • max_features: 최상의 분할을 찾을 때 고려할 최대 특성 수
  • min_samples_leaf: 리프 노드가 되기 위해 필요한 최소 샘플
  • max_depth (최대깊이): 트리의 최대 깊이를 나타냅니다. None으로 설정하면 노드가 더 이상 분할되지 않을 때까지 깊이가 계속 확장
  • min_samples_split (최소 노드 크기): 노드를 분할하기 위한 데이터 수, 해당 노드에 이 값보다 적은 샘플이 있다면 분할을 중지
  • min_impurity_decrease (최소 향상도): 노드를 분할하기 위한 최소 향상도, 향상도가 설정값 이하라면 더 이상 분할하지 않습니다.
  • ccp_alpha (비용복잡도): 트리의 비용복잡도에 대한 패널티를 나타냅니다. 클수록 더 간단한 트리를 선호
model = RandomForestRegressor(random_state=2020)

params = {'n_estimators': [200, 300, 500],
          'max_features': [5, 6, 8],
          'min_samples_leaf': [1, 3, 5],
          'max_depth': [None, 10, 20, 30],  # 최대깊이
          'min_samples_split': [2, 5, 10],   # 최소 노드 크기
          'min_impurity_decrease': [0.0, 0.1, 0.2],  # 최소 향상도
          'ccp_alpha': [0.0, 0.1, 0.2]}  # 비용복잡도

 

근데 파라미터를 너무 많이 설정해서 경우의 수가 너무 많아졌는지,,,47분동안 모델이 학습을 못하길래 파라미터를 줄여 재시도

from sklearn.model_selection import GridSearchCV

model = RandomForestRegressor(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)

 

sumission.head()

 

 

(3) GridSearchCV 객체를 생성해 모델 학습

  • model: 튜닝하려는 머신 러닝 모델 (RandomForestRegressor 이 경우)
  • param_grid: 하이퍼파라미터 및 그들의 가능한 값들을 담은 딕셔너리
  • cv: 교차 증을 위한 폴드 수, 데이터를 여러부분으로 나누어 모델을 훈련해서 성능 지표를 얻음. cv = 5면, 전체 데이터가 5개로 나누며 4개의 폴드는 훈련에 1개는 검증에 사용되는 과정을 5번반복하여 모델의 성능을 평가. 보통 3~10값을 가지며, 5 또는 10을 선택
  • n_jobs: 병렬 처리를 위해 사용할 CPU 코어의 수 (-1은 가능한 모든 코어를 사용하라는 의미)
greedy_CV = GridSearchCV(model, param_grid=params, cv = 3, n_jobs = -1)
greedy_CV.fit(X_train, Y_train)

 

 

GridSearchCV 객체로 학습한 모델 test 데이터에 적용

pred = greedy_CV.predict(test)
pred