Random Forest (Decision Tree)

Impurity

만약 초록 동그라미와 주황 네모를 두 상자에 분류하는 문제를 푼다고 가정하자. A와 B를 비교했을 때 A가 더 잘 분류했다고 할 수 있다. 그 이유는 A의 두 상자 안에 들어있는 도형이 더 일관성 있기 때문이다. 이러한 개념을 불순도(impurity)로 설명한다. 위 상황에서는 B의 불순도가 더 높다고 할 수 있다. 그리고 불순도를 나타내는 대표적인 지표가 엔트로피(entropy)지니 불순도(Gini impurity)이다. 

Entropy

$Entropy(t)=-\sum_i^c p(i|t)log_2p(i|t)$

Gini Impurity

$Gini(t)=1-\sum_i^c p(i|t)^2$

* p(i|t)노드 t에서 i 레이블에 속한 데이터의 비율을 뜻한다. 

계산 예시

데이터: [ 1, 1, 0, 1, 0 ]

$Entropy=-\cfrac{3}{5}log_2\cfrac{3}{5}-\cfrac{2}{5}log_2\cfrac{2}{5}$

>>> import numpy as np
>>> entropy = -(0.6 * np.log2(0.6)) - (0.4 * np.log2(0.4))
>>> entropy
0.9709505944546686

두 지표 모두 균일하게 분류되어 있을수록 큰 값을 가진다. 엔트로피는 0.0~1.0, 지니 불순도는 0.0~0.5를 가진다. 


Decision Tree

결정 트리(Decision Tree)는 불순도의 개념을 활용해 분류를 진행한다. 

여러 특징 중 불순도를 가장 크게 낮추는 특징을 찾아 먼저 구분한다. 그리고 이 과정을 반복한다. 이때 사용하는 개념이 정보 이득(Information Gain)이다. 

Information Gain (IG)

$IG = I_{(parent)}-\cfrac{N_{left}}{N_{parent}}I_{(left\ child)}-\cfrac{N_{right}}{N_{parent}}I_{(right\ child)}\\
=I_{(p)}-\sum_{j=1}^{m}\cfrac{N_{j}}{N_{p}}I_{(j)}$

I(Node)는 엔트로피나 지니와 같은 불순도 지표를 뜻한다. 즉, 정보 이득이란 '부모 노드에 비해 얼마나 불순도가 낮아졌는가'를 뜻한다. 

위 예시 그림에서도 알 수 있듯이 결정 트리는 다른 머신러닝 기법과 달리 분류 기준을 명확히 설명할 수 있다는 장점이 있다. 하지만 주의할 것은 트리의 깊이가 깊어질 경우 오버 피팅이 발생할 수 있기 때문에 트리의 깊이를 제한할 필요가 있다. 


Random Forest

랜덤 포레스트(Random Forest)는 앞서 본 결정 트리의 확장된 버전이다. 

Bootstrap은 중복을 허용하고 랜덤하게 추출한 데이터를 뜻한다. 즉, 하나의 데이터로부터 여러 변형을 만들어 내는 것이다. 그리고 분할된 데이터를 이용해 여러 결정 트리를 만든다. 이렇게 하면 현재 데이터에 의존하지 않고 다양한 상황을 반영하여 결정할 수 있다. 다시 말해 오버 피팅 문제를 감소시킨다. 이러한 앙상블 기법을 Bootstrap Aggregating 또는 Bagging이라고 한다. 

최종적으로 각각의 결정 트리가 예측한 분류를 다수결(majority voting)에 따라 결정한다. 


Decision Tree & Random Forest

sklearn wine dataset

sklearn에서 제공하는 wine 데이터셋을 활용해 분류한 모습이다. 

Decision Tree Random Forest

분류된 모습을 보면 Random Forest가 더 정밀하게 분류한 것을 볼 수 있다. 

 

Sklearn

from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score


wine = datasets.load_wine()
X = wine.data[:, [6, 9]]
y = wine.target
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=1, stratify=y
)


def print_acc(model):
    y_pred = model.predict(X=X_test)
    acc = accuracy_score(y_test, y_pred)
    print(f"accuracy: {acc:.3f}\n")


# 모델 학습 및 확인
print("< Decision Tree Classifier >")
tree_model = DecisionTreeClassifier(criterion="gini", max_depth=4, random_state=1)
tree_model.fit(X_train, y_train)
print_acc(tree_model)

print("< Random Forest Classifier >")
forest = RandomForestClassifier(
    criterion="gini", n_estimators=20, random_state=1, n_jobs=2
)
forest.fit(X_train, y_train)
print_acc(forest)
< Decision Tree Classifier >
accuracy: 0.926

< Random Forest Classifier >
accuracy: 0.944

 

from sklearn import tree
import matplotlib.pyplot as plt 

tree.plot_tree(tree_model)
plt.show()