[Python] Ensemble(앙상블) - Random Forest(랜덤포레스트)

2020. 7. 31. 19:34ML in Python/Python

 

 이 게시글은 오로지 파이썬을 통한 실습만을 진행한다. 앙상블 기법중 RandomForest의 개념 및 원리를 알고자하면 아래 링크를 통해학습을 진행하면 된다.

https://todayisbetterthanyesterday.tistory.com/48?category=822147

 

[Data Analysis 개념] Ensemble(앙상블)-2 : Bagging, RandomForest

 앙상블에 대한 종류와 전반적인 설명은 아래 링크에 존재한다. 이 게시글에서는 앙상블 모형중 Bagging과 RandomForest에 대해서 알아보겠다. https://todayisbetterthanyesterday.tistory.com/47 [Data Analysi..

todayisbetterthanyesterday.tistory.com

 

 

 실습에 사용할 데이터는 아래의 데이터이다. kaggle에서 제공하는 데이터이며, 상세한 내용은 아래와 같다. 

otto_train.zip
1.69MB

id: 고유 아이디
feat_1 ~ feat_93: 설명변수
target: 타겟변수 (1~9)

 RandomForest는 Bagging 기법에 학습 모델의 분산을 줄이기 위해서, 변수까지 특정 개수로 무작위 추출을 하는 방법으로 학습을 진행한다. RandomForest는 Tree기반의 앙상블 기법으로 sklearn을 통해 간단하게 구현이 가능하다. 그럼에도 불구하고, 보통 좋은 성능을 갖는다고 알려져있다. 

 이 RandomForest에 대해서 Python을 활용한 실습을 진행해보자.


1. 데이터 처리

 

# data 처리를 위한 library

import os 
import pandas as pd 
import numpy as np
from sklearn.model_selection import train_test_split
# 현재경로 확인

os.getcwd()

 위의 코드는 파이썬 해당파일(.py / .ipynb)의 위치경로를 표기해주는 것이다. 만약 데이터가 다른 경로에 존재한다고 하였을 때, 전 경로를 확인하기 위해서 자주 사용한다. 

# 데이터 불러오기
# kaggle data

data = pd.read_csv("./otto_train.csv")
data.head()

 먼저 이 kaggle데이터는 target변수가 class_1~9까지 문자형식으로 되어있다. 그렇기에 이 문자형식의 target을 수치형 데이터(1~9)로 변환해줄 필요가 있다. 

 또한 이 kaggle데이터는 기업 및 단체가 데이터를 제공하기에 위와 같이 feature에 대한 정보를 알 수 없도록 해놓았다. 이를 통해 파이썬 실습을 진행할 것이다.  

# shape확인

nCar = data.shape[0] # 데이터 개수
nVar = data.shape[1] # 변수 개수
print('nCar: %d' % nCar, 'nVar: %d' % nVar )

  otto_train 데이터에는 61878개의 행과 95가지의 변수가 존재한다. target을 제외하면 94가지 features가 존재하는 것이다. 먼저 target의 형변환을 해주어고 무의미한 변수를 제거해야한다.

# 무의미한 변수 제거

data= data.drop(['id'],axis=1)
# 타겟 변수의 형변환

mapping_dict = {'Class_1' : 1,
                'Class_2' : 2,
                'Class_3' : 3,
                'Class_4' : 4,
                'Class_5' : 5,
                'Class_6' : 6,
                'Class_7' : 7,
                'Class_8' : 8,
                'Class_9' : 9,}
after_mapping_target = data['target'].apply(lambda x : mapping_dict[x])
after_mapping_target

 target의 형태가 "Class_1" - 1 ~ "Class_9" - 9 로 변환되었다. 이를 통해서 이제 classification을 진행할 것이다.  

# features/target, train/test dataset 분리

feature_columns = list(data.columns.difference(['target']))
X = data[feature_columns]
y = after_mapping_target

train_x, test_x, train_y, test_y = train_test_split(X, y, test_size = 0.2, random_state = 42) # 학습데이터와 평가데이터의 비율을 8:2 로 분할| 
print(train_x.shape, test_x.shape, train_y.shape, test_y.shape) # 데이터 개수 확인

 

 

2. Random Forest 적합

 

Random Forest

#기본적인 randomforest모형

from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score # 정확도 함수

clf = RandomForestClassifier(n_estimators=20, max_depth=5,random_state=0)
clf.fit(train_x,train_y)

predict1 = clf.predict(test_x)
print(accuracy_score(test_y,predict1))

 

 위의 Random Forest는 트리의 깊이를 5로 제한하고 20개의 Sampling을 통해 학습을 진행한다. 그 결과 정확도가 59%정도 나왔다. 분류기로 사용하기에는 좋지않은 정확도이다. 

 

Random Forest Sample개수 증가

# sample 100개, tree depth - 20

clf = RandomForestClassifier(n_estimators=100, max_depth=20,random_state=0)
clf.fit(train_x,train_y)

predict2 = clf.predict(test_x)
print(accuracy_score(test_y,predict2))

 위의 경우에는 sample개수를 100개로 늘렸다. 그랬더니 정확도가 대략 78%까지 증가하였다. 그렇다면 무한하게 많이 sample개수를 증가시키면 되지 않는가? 하는 생각이 들 수도 있다. 하지만, sample개수가 증가한다고 하여서 무작정 성능이 향상되지는 않는다. 아래 경우를 보자

 

# sample 300개, tree depth - 20

clf = RandomForestClassifier(n_estimators=300, max_depth=20,random_state=0)
clf.fit(train_x,train_y)

predict2 = clf.predict(test_x)
print(accuracy_score(test_y,predict2))

 위의 경우는 샘플 개수를 300개까지 늘린 것이다. 그랬더니 성능이 100개보다 좋지 않는 61% 정도로 떨어졌다. 이것은 ML의 전반적인 특성이기도 하다. 무작정 학습의 반복횟수/sample개수를 늘린다는 것이 성능의 향상을 장담하지는 않는다. 그렇기에 해당 데이터에 맞는 선정 모델의 parameter은 분석가가 경험적으로 찾거나, 아니면 해당 분야에서 통상적으로 쓰이는 parameter를 알아야한다. 

 그렇다면 위의 모델에서 최적의 n_estimators parameter가 100이라고 가정하고, 이번에는 트리의 깊이를 늘려보자. 

 

Random Forest Tree 깊이 증가

# sample 100개, tree depth - 100(max)

clf = RandomForestClassifier(n_estimators=100, max_depth=100,random_state=0)
clf.fit(train_x,train_y)

predict2 = clf.predict(test_x)
print(accuracy_score(test_y,predict2))

위의 결과를 보면 sample개수가 100개이고, 깊이를 최대로 허용하였을때, 정확도가 대략 81%까지 상승하였다. 물론 RandomForest를 포함한 ensemble모형에는 수많은 parameter들이 존재하기에 다른 parameter의 최적값 또한 찾아낸다면 더 좋은 성능을 발휘할 것이다. 

 하지만 그렇게되면 설명을 해야할게 너무 많아지기에 아래 sklearn 링크를 통해서 알아보기를 추천한다. 

https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html

 

3.2.4.3.1. sklearn.ensemble.RandomForestClassifier — scikit-learn 0.23.1 documentation

 

scikit-learn.org