[ 핸즈온 머신러닝 2 ] Decision Tree란?
어제보다 나은 사람이 되기

걱정보단 실행을, 그러나 계획적으로

Box World 자세히보기

AI/Hands-On Machine Learning 2판

[ 핸즈온 머신러닝 2 ] Decision Tree란?

Box형 2021. 2. 2. 17:07
반응형

성공하려면 이미 했던 일을 제대로 활용하라

- 블레이크 로스 (파이어폭스 공동 개발자) -


시작하며

 저번 포스팅에서는 SVM에 대해 다뤄보았습니다. 이번 포스팅에서 다룰 Decision Tree은 SVM처럼 Classification, Regression 등 폭넓게 사용이 가능하며, 복잡한 데이터셋도 학습할 수 있는 강력한 알고리즘입니다.


 6.1 Decision Tree 학습과 시각화

 우선 Decision Tree를 이해하기 위해 모델 하나를 생성한 후 어떻게 예측하는지 살펴보겠습니다. 데이터는 Iris(붓꽃의 종류를 클래스화한 데이터)를 사용하였습니다.

from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier

iris = load_iris()
X = iris.data[:, 2:] # 꽃잎 길이와 너비
y = iris.target

tree_clf = DecisionTreeClassifier(max_depth=2, random_state=42)
tree_clf.fit(X, y)

//output
DecisionTreeClassifier(max_depth=2, random_state=42)

 export_graphviz() 함수는 Decision Tree를 시각화하여 .dot 파일의 형태로 출력합니다.

from graphviz import Source
from sklearn.tree import export_graphviz

export_graphviz(
        tree_clf,
        out_file=os.path.join(IMAGES_PATH, "iris_tree.dot"),
        feature_names=iris.feature_names[2:],
        class_names=iris.target_names,
        rounded=True,
        filled=True
    )

Source.from_file(os.path.join(IMAGES_PATH, "iris_tree.dot"))


 6.2 예측하기

 위 Decision Tree가 어떻게 예측을 하는지 살펴보면서 그래프를 분석해보겠습니다.

  먼저 데이터가 들어오면 루트 노드(Depth = 0)를 가장 먼저 거치게 됩니다. 이 노드는 꽃잎의 길이(petal length)가 2.45cm보다 짧은지 검사합니다. 만약 그렇다면(=True)왼쪽 자식 노드(Depth = 1)로 이동합니다.

 그리고 이동한 자식 노드가 리프 노드(자식 노드를 가지지 않은 노드)라면 추가적인 검사를 하지않고 해당 노드에 적힌 class인 "senota"라고 예측합니다.

 이번엔 꽃잎의 길이가 2.45cm보다 긴 데이터가 들어와 루트에서 오른쪽 자식 노드로 이동했다고 가정해보겠습니다. 그러면 해당 노드는 리프 노드가 아니기 때문에 꽃잎의 길이가 1.75cm보다 작은지 검사하게 됩니다. 검사 후 데이터는 어느 리프노드로 내려가냐에 따라 "versicolor"혹은 "virginica"가 될것입니다.

 

더보기

NOTE_ Decision Tree의 장점 중 하나는 Data 전처리가 거의 필요하지 않다는 것입니다. 즉 feature의 Scale을 조정하구나 평균을 원점에 맞추는 작업을 요하지 않습니다.


 이제 나머지 노드의 구성요소에 대해서 살펴보겠습니다.

 sample 속성은 해당 노드로 얼마나 많은 데이터가 내려왔는지를 헤아린 것입니다. 예를 들어 앞서 본 Tree의 보라색 노드의 sample = 46이므로 46개의 데이터가 이 노드로 내려왔다는 것을 알 수 있습니다.

 value 속성은 어떤 클래스의 데이터가 해당 노드로 내려왔는지 알려줍니다. 보라색 노드의 value = [0, 1, 45]이므로 Setosa 클래스를 가지는 데이터는 0개, Versicolor는 1개, Virginica는 45개가 해당 노드로 내려왔다고 판단하게 됩니다.

 마지막으로 gini불순도(impurity)를 측정합니다. 보통 우리가 물에 이물질이나 흙이 많이 섞여있으면 불순도가 높다고 하는데 여기서도 비슷한 맥락을 가집니다. 예를 들어 한 노드를 지나간 데이터들이 모두 같은 클래스라면 이때의 gini = 0이라고 할 수 있습니다. 

 불순도를 구하는 방법에는 여러가지가 있지만 가장 보편적인 것은 '지니 불순도'입니다.

 이 식을 이용하면 그래프의 초록색 노드의 불순도는 다음처럼 구할 수 있습니다.


 위그림은 Decision Tree의 결정 경계를 보여줍니다. 굵은 수직선이 루트 노드의 결정 경계(꽃잎 길이 = 2.45cm)를 나타냅니다. 앞선 코드에서 max_depth를 2로 설정했었는데 만약 3으로 설정하면 점선으로 보이는 경계가 추가로 만들어집니다.


 6.2 클래스 확률 추정

Decision tree는 데이터가 특정 클래스 k에 속할 확률을 추정할 수도 있습니다.

1) 데이터가 속한 리프 노드를 찾기 위해 트리를 탐색합니다.

2) 해당 노드를 지나간 데이터들 중에서 클래스 k의 비율을 반환합니다. 

예를 들어 length = 5cm이고, width = 1.5cm인 꽃잎은 초록색 노드입니다. 따라서 Setosa일 확률은 0%(0/54), Versicolor는 90.7%(49/54), Virginica는 9.3%(5/54)입니다. 다음 코드에서 방금 예시로 든 데이터를 예측했을 때 Versicolor(class = 1)이 나오는 것을 확인할 수 있습니다.

tree_clf.predict_proba([[5, 1.5]])
>> array([[0.        , 0.90740741, 0.09259259]])

tree_clf.predict([[5, 1.5]])
>> array([1])

 6.4 CART 훈련 알고리즘

 Sklearn에서는 Decision Tree 학습을 위해 CART 알고리즘을 사용합니다. 첫번째는 Training set에서 꽃잎의 길이와 같은 하나의 feature를 고른 후, <= 2.45cm같이 노드를 가르는 임곗값 $t_k$를 사용하여 두 개의 subset으로 나눕니다. 

 이때의 feature는 Training set 내 클래스 비율을 고려하여 가장 순수하게 서브셋으로 나눌 수 있는 feature와 $t_k$를 찾습니다. 

 알고리즘이 최소화할 비용함수는 다음과 같습니다.

 Training set을 성공적으로 둘로 나눈 알고리즘은 max_depth까지 도달하거나, gini(불순도)를 줄이는 분할을 찾을 수 없을 때 멈추게 됩니다.


 6.5 엔드로피 불순도

 sklearn에서는 criterion = "entropy"으로 지정하면 지니 불순도가 아닌 엔트로피 불순도를 사용하게 됩니다.

 지니 불순도가 좀 더 계산이 빠르기 때문에 기본적으로 좋지만, 엔트로피는 좀 더 균형 잡힌 트리를 만드는데 용이하다는 장점을 가지고 있습니다.


 6.7 규제 파라미터

 Decision Tree는 Training data에 대한 제약이 거의 없습니다. 따라서 제한을 두지 않으면 트리는 데이터에 Overfitting되기 쉽습니다. 

 Decision tree는 학습 전 파라미터의 수가 결정되지 않아 비파라미터 모델(nonparameter model)이라고 부르고, 모델의 구조가 자유롭습니다. 반대로 Linear model과 같은 파라미터 모델(parameter model)은 Overfitting될 위험이 줄어듭니다.

이러한 Overfit을 막기 위해 max_depth와 같은 규제 파라미터를 사용합니다. 이 외에도 sklearn의 DecisionTreeClassifier에서는 다른 규제 파라미터가 있습니다.

- min_samples_leaf : 리프 노드가 가져야할 최소 샘플 수

- min_weight_graction_leaf : min_samples_leaf와 같지만, 가중치가 부여된 전체 데이터 수에서의 ㅂ율

- max_leaf_nodes : 리프 노드의 최대 수

- max_features : 각 노드에서 분할에 사용할 특성의 최대 수

 다음은 규제 파라미터의 효과를 관찰하기 위해 moons 데이터셋에 규제가 없는 것과 min_samples_leaf = 4로 설정한 것 두개의 Decision tree입니다. 확실히 왼쪽 그래프가 Overfitting되어있는 것을 확인할 수 있습니다.


 6.8 Regression

 이번엔 Decision Tree를 Regression에 활용하는 법을 공부해보습니다. sklearn의 DecisiontreeRegressor를 이용해 feature가 2개인 데이터셋에 대해 max_depth = 2로 설정하고 트리를 생성하였습니다.

from sklearn.tree import DecisionTreeRegressor

tree_reg = DecisionTreeRegressor(max_depth=2, random_state=42)
tree_reg.fit(X, y)

>> DecisionTreeRegressor(max_depth=2, random_state=42)

 앞서 Classification을 위해 사용된 Decision Tree와 크게 차이가 있어보이진 않습니다. 다만 Regression에서는 들어온 데이터가 어느 클래스인지를 분류하는 대신 어떤 값을 예측한다는 점에서 차이가 있습니다.

 예를 들어 $x_1 = 0.6$인 데이터의 타깃값을 예측한다면, 루트 노드에서부터 value가 0.111인 리프 노드에 도달하게 됩니다. 그리고 해당 리프 노드로 도달한 110개 데이터의 평균 타깃값이 예측값이 됩니다. 이를 이용하여 MSE를 계산하면 0.015가 나오게 됩니다. 


 위 그래프들은 서로 다른 max_depth에 대한 Decision Tree 모델이고, 빨간색 선이 데이터를 대표하는 회귀 그래프입니다. 각 영역의 예측값 $\hat{y}$는 해당 영역에 있는 타깃값 $y$의 평균입니다.

 CART 알고리즘은 불순도를 최소화하는 대신 다음과 같이 MSE를 최소화하도록 분할합니다.

 Regression에서도 Decision Tree는 Overfitting되기 쉽기 때문에 규제 파라미터를 이용하면 다음과 같이 훨씬 그럴싸한 모델을 생성할 수 있습니다.


 6.9 Decision Tree의 단점 : 불안정성

 Decision Tree의 결정 경계는 계단 모양입니다. 이 말은 Training set의 사소한 변화에도 민감하다는 의미입니다. 예를 들어 데이터셋을 45C˚ 회전하게 되면 Decision Tree는 다음 오른쪽처럼 불필요하게 구불구불해집니다.

 또 다른 예시는 앞서 본 Iris 데이터에서 Versicolor 클래스를 제거하고 훈련시켰을 때의 모델입니다. 분명 이전에 만든 Decision Tree와는 다른 모습을 보이는 문제가 있습니다.


다음 포스팅에서는 앙상블 학습과 랜덤 포레스트에 대해서 공부해보겠습니다. 긴 글 읽어주셔서 감사합니다. 오늘도 행복한 하루 보내시길 바랍니다 :)

반응형