랜덤포레스트(Random Forest)

랜덤포레스트는 의사결정트리(Decision Tree)와 닮은 점이 많은 지도학습 예측모델입니다. 두 모델 모두 어떤 질문에 의해서 데이터 셋을 분리하는(가지를 만드는) 기본적인 방식은 닮았지만 의사결정나무가 전체 데이터를 통해서 성능이 좋은 하나의 나무를 만드는데 목적이 있다면 램덤포레스트는 하나의 나무를 만들기 보다는 데이터셋을 랜덤하게 샘플링해서 여러개의 예측 모델을 만들고 그 이러한 모델들을 종합해서 하나의 예측 결과를 리턴하는 방법으로 최종 예측을 수행합니다.

이러한 과정을 Bagging(= Bootstrap + Aggregation)이라고 합니다. 즉, 주어진 하나의 큰 데이터를 여러 개의 부트스트랩 자료(중복허용)를 생성하고 각 부트스트랩 자료를 모델링한 결과를 통합하여 최종의 예측 모델을 산출하는 방법입니다. 이런 예측 모델은 데이터가 변동성이 큰 경우 원자료(Raw Data)로부터 여러번의 샘플링읕 통해서 예측 모델의 정확도를 높이는 기법입니다. 이런 과정을 통해서 n개의 예측 모델이 만들어집니다. 그러나 결국 필요한 것은 하나의 데이터이기 때문에 각각의 모델의 결과 값에 대해서 회귀분석(평균계산)을 하던가 과반 투표(분류 모델)를 통해서 최종 결과 값을 만들게 됩니다.
이러한 방법의 알고리즘 중에 가장 대표적인 모델이 바로 랜덤포레스트(Random Forest)입니다.

이러한 복잡한 알고리즘을 sklearn의 ensemble 패키지의 RandomForestClassifier에서 훌륭하게 구현하고 있습니다.

import numpy as np
import pandas as pd

from sklearn.datasets import make_blobs, make_classification
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt

테스트 데이터 생성을 위해서 sklearn의 make_classification를 사용하겠습니다. 데이터의 수는 총 300개, feature는 5개이며이며 각각의 feature는 종속변수와 상관관계가 존재합니다. 해당 데이터 셋의 클러스터는 1이고 데이터의 클래스는 3입니다. 즉, 최종 예측은 0,1,2 이 셋 중에 하나의 값을 가진다는 뜻입니다.

위에 보면 등분산성 데이터를 만들어주는 make_blobs()를 사용한 부분이 있는데 이렇게 하면 데이터가 분류에 너무 최적화 되어 있기 때문에 make_classification()을 사용합니다.

#x, y = make_blobs(n_samples=300, n_features=5, centers=3) 
x, y = make_classification(n_samples=300, n_features=5, n_informative=5, n_redundant=0, n_clusters_per_class=1, n_classes=3)

데이터 셋을 만든 다음 모델의 정확도를 검증하기 위해서 train, test 데이터 셋으로 분리합니다. 분리는 8:2 정도로 하겠습니다.

x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.2, random_state=0) # 8:2
print(x_train.shape, x_test.shape)
# (240, 5) (60, 5)

sklearn에 보면 RandomForestClassifier를 만드는데 몇가지 파라메터들이 있습니다. 그중에 예제에서는 n_estimators(The number of trees in the forest.)를 사용합니다. 해당 파라메터는 하나의 나무를 만드는 의사결정나무(Decision-Tree)와는 다르게 여러개의 모델을 만드는 RandomForest의 특징입니다. 나무를 많이 만들면 예측의 정확도는 높아 질 수 있지만 그만큼 많은 자원을 필요로 하고 또 일정 수준 이상으로는 높아지지 않기 때문에 가능하면 테스트를 하면서 수를 늘려가는 방식으로 수행하는 것을 추천합니다.

해당 모델은 데이터셋이 비교적 구분이 잘되어 있는 데이터셋이기 때문에 10으로 셋팅합니다.

from sklearn.ensemble import RandomForestClassifier
randomfc = RandomForestClassifier(n_estimators=10).fit(x_train, y_train)
randomfc
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
                       max_depth=None, max_features='auto', max_leaf_nodes=None,
                       min_impurity_decrease=0.0, min_impurity_split=None,
                       min_samples_leaf=1, min_samples_split=2,
                       min_weight_fraction_leaf=0.0, n_estimators=10,
                       n_jobs=None, oob_score=False, random_state=None,
                       verbose=0, warm_start=False)

모델의 정확도는 85%로 측정되었습니다. 데이터 셋은 랜덤으로 만들어지기 때문에 만들 때마다 정확도가 다르게 측정됩니다.

predict = randomfc.predict(x_test)
print(randomfc.score(x_test, y_test))
# 0.85

더 자세한 결과를 보기 위해서 confusion_matrix를 체크해봅니다. 2~4개의 오차가 발견되지만결과 관대한 저에게는 대부분 정확하게 예측을 한것으로 보입니다. (다르게 보일 수도 있습니다.)

from sklearn.metrics import confusion_matrix
confusion_matrix(y_test, predict)
# output #
array([[14,  1,  3],
       [ 1, 18,  1],
       [ 3,  0, 19]])

classification_report를 통해서 결과를 더 자세히 살펴보겠습니다. 각각의 용어들은 아래와 같은 의미가 있습니다.

정확도(accuracy) : 예측한 값의 몇개를 맞췄는가?
정밀도(precision) : 예측한 것중에 정답의 비율은?
재현율(recall) : 정답인 것을 모델이 어떻게 예측했는가?
F1 Score : 정밀도와 재현율의 가중조화평균(weight harmonic average)을 F점수(F-score)라고 정의합니다. 즉, F1 Score 값이 높으면 성능이 높다고 할 수 있습니다.

from sklearn.metrics import classification_report
report = classification_report(y_test, predict)
# output #
              precision    recall  f1-score   support

           0       0.78      0.78      0.78        18
           1       0.95      0.90      0.92        20
           2       0.83      0.86      0.84        22

    accuracy                           0.85        60
   macro avg       0.85      0.85      0.85        60
weighted avg       0.85      0.85      0.85        60

이제 랜덤하게 생성된 임의의 데이터가 아닌 load_digits 데이터셋을 활용해보도록 하겠습니다. 해당 데이터셋에 대한 설명은 생략하겠습니다.

from sklearn.datasets import load_digits
digits = load_digits()

x_train, x_test, y_train, y_test = train_test_split(digits.data, digits.target, test_size = 0.2, random_state=0) # 8:2
print(x_train.shape, x_test.shape)
# (1437, 64) (360, 64)
randomfc = RandomForestClassifier(n_estimators=10).fit(x_train, y_train)
print(randomfc.score(x_test, y_test) )
# 0.9472222222222222
predict = randomfc.predict(x_test)
confusion_matrix(y_test, predict)

array([[27,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 0, 34,  0,  0,  0,  1,  0,  0,  0,  0],
       [ 1,  0, 33,  2,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0, 29,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  0, 28,  0,  0,  2,  0,  0],
       [ 0,  0,  0,  0,  0, 39,  0,  0,  1,  0],
       [ 0,  1,  0,  0,  0,  0, 42,  0,  1,  0],
       [ 0,  0,  0,  0,  0,  0,  0, 38,  1,  0],
       [ 0,  2,  0,  2,  0,  0,  0,  0, 35,  0],
       [ 0,  3,  0,  1,  0,  0,  0,  1,  0, 36]])
report = classification_report(y_test, predict)
print(report)

              precision    recall  f1-score   support

           0       0.96      1.00      0.98        27
           1       0.85      0.97      0.91        35
           2       1.00      0.92      0.96        36
           3       0.85      1.00      0.92        29
           4       1.00      0.93      0.97        30
           5       0.97      0.97      0.97        40
           6       1.00      0.95      0.98        44
           7       0.93      0.97      0.95        39
           8       0.92      0.90      0.91        39
           9       1.00      0.88      0.94        41

    accuracy                           0.95       360
   macro avg       0.95      0.95      0.95       360
weighted avg       0.95      0.95      0.95       360

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 항목은 *(으)로 표시합니다