이번 포스팅에서는 혼공머신이 결정 트리 알고리즘에 대해 설명한 내용을 리뷰해보도록 하겠습니다.
결정 트리(Decision Tree)는 머신러닝에서 쉽지만 성능이 좋은 알고리즘 중 하나입니다.
노드와 엣지로 구성된 트리 형식입니다. 맨 위의 노드를 루트 노드(root node)라고 하고,
맨 아래 달린 노드를 리프 노드(leaf node)라고 합니다. 각 노드를 엣지로 연결하여 구성됩니다.
결정 트리에서 각 노드는 훈련 데이터의 특성에 대한 테스트를 표현합니다.
예를 들면 키가 170보다 크다 or 작다로 키에 대한 테스트를 표현하는 것입니다.
이 때 테스트 결과를 True or False로 나타내며 일반적으로 하나의 노드는 두 개의 결과(가지,Branch)를 가집니다.
그 구조를 전체적으로 살피면 Flowchart의 구조를 가집니다.
즉, 스무고개를 하는 형식과 비슷한데 질문에 답을 하면서 정답에 가까워지는 형식입니다.
기본적으로 결정트리는 지도 학습 모델입니다. 답을 가진 데이터의 규칙을 학습하는 꼴 입니다.
실제 코드를 통해 예시를 들어 보겠습니다.
데이터는 와인 데이터로 혼공머신 깃허브에 저장되어 있습니다.
와인 데이터에는 알코올 도수, 당도, 산도, class에 대한 값들이 있습니다.
class에는 화이트 와인, 레드 와인이 있습니다.
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.tree import DecisionTreeClassifier
wine = pd.read_csv('https://bit.ly/wine_csv_data')
#넘파이 배열로 변환
data = wine[['alcohol', 'sugar', 'pH']].to_numpy()
target = wine['class'].to_numpy()
train_input, test_input, train_target, test_target = train_test_split(data, target, test_size=0.2, random_state=42)
#결정트리 적용
dt = DecisionTreeClassifier(random_state = 42)
dt.fit(train_scaled, train_target)
print(dt.score(train_scaled, train_target))
만들어진 결정 트리 모델을 시각화 할 수 있습니다.
시각화를 통해 각각의 트리 노드를 해석할 수 있습니다.
코드는 다음과 같습니다.
import matplotlib.pyplot as plt
from sklearn.tree import plot_tree
plt.figure(figsize=(10,7))
plot_tree(dt, max_depth=1, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()
사이킷런의 plot_tree()함수가 그 역할을 수행합니다.
각각의 매개변수를 설명하면,
max_depth = 1 -> 트리 깊이를 1로 지정(=루트 노드 제외하고 하나의 노드까지만 확장)
filled = True -> 구분된 클래스의 값이 많아질 수록 특정 색을 진하고 연하게 칠함
feature_names = [alcohol', 'sugar', 'pH'] -> 질문을 할 때 특성의 이름을 반영함(안쓰면 인덱스로 표현한다.X[1]이런 식)
실행 결과는 그림 1과 같습니다.
이를 해석하는 방법은 다음 그림과 같습니다.
클래스별 샘플 수는 조건을 만족하는 각 클래스별 샘플 수를 의미합니다.
가령, [1258, 3939]로 표현된다면
이전 노드의 조건을 만족하는 클래스0의 샘플수가 1258개, 클래스1의 샘플수가 3939개라는 의미입니다.
결정 트리에서는 데이터를 잘 구분 짓는 질문을 잘 정해야 할 것입니다.
물론 좋지 않은 질문을 계속, 많이 하면 구분을 잘 지을 수 있습니다.(꼭 그런것만은 아님)
하지만 좋은 질문을 하면 더욱 적게 질문하면서 분류 정확도를 효율적으로 높일 것 입니다.
이를 확인 할 수 있는 방법은 불순도를 측정하는 것 입니다.
여기서는 지니 불순도(Gini impurity)로 설명하겠습니다.
어떠한 조건으로 분류를 했을 때 클래스가 한 쪽으로 치우쳐서 분류가 됐다면 좋은 조건으로 분류를 했다고 볼 수 있을 것입니다.
지니 불순도를 쉽게 설명하면 데이터가 얼마나 깨끗한지(ex)한 종류의 데이터만으로 되어있는 것)를 나타내는 것입니다.
0일수록 지니 불순도가 낮아 데이터는 깨끗한 것이며, 0.5일수록 가장 혼잡하게 구성되어 있는 것을 의미합니다.
앞선 코드로 구현한 트리에서 루트 노드는 sugar <= -0.239로 질문을 던졌습니다.
이 때 지니 불순도를 사용하여 이러한 기준을 세운 것 입니다.
지니 불순도는 클래스의 비율을 제곱해서 더한 다음 1에서 빼 계산합니다.
(예시,이진 분류: 지니 불순도 = 1 -(음성 클래스 비율의 제곱 + 양성 클래스 비율의 제곱) )
여기서 알 수 있듯이 0.5의 지니 불순도가 나오려면
100개의 샘플이 있는 어떤 노드의 두 클래스 비율이 정확히 50개, 50개 있을 때여야 합니다.
두 개의 클래스가 가장 혼잡하게 구성되어 있는 것이죠.
만약 100개, 0개이면 지니 불순도는 0이 될 것 입니다.
이러한 노드를 순수 노드라고 부릅니다.
결정 트리 모델은 부모 노드와 자식 노드의 불순도 차이를 가장 크게 만들면서 트리를 확장합니다.
그 차이는 다음과 같이 계산합니다.
이를 정보 이득(information gain)이라고 부르며, 정보 이득이 클 수록 잘 구분한 것을 의미합니다.
스무 고개에서 답을 바로 알아차릴 만한 좋은 질문을 한 것과 같습니다.
그럼 결정 트리라는 것은 정보 이득을 크게 갖는 조건들을 데이터로 부터 학습하는 모델이겠군요.
하지만 질문을 계속해서 한다면 무작정 자라나는 트리가 생성 될 것입니다.
그럼 당연히 훈련 세트에 대해 과적합되는 모습을 보일 것 입니다.
따라서 우리는 일반화를 위해 가지치기(Pruning)를 해야합니다.
결정 트리에서 가지치기 하는 방법은 DecisionTreeClassifier 클래스의 max_depth 매개변수를 지정하는 것입니다.
코드는 다음과 같습니다.
dt = DecisionTreeClassifier(max_depth=3, random_state=42)
dt.fit(train_input, train_target)
print(dt.score(train_input, train_target))
print(dt.score(test_input, test_target))
plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()
뿐만 아니라 결정 트리는 어떠한 특성이 클래스를 분류하는데 가장 중요한지 그 중요도를 계산해줍니다.
결정 트리 모델에 feature_importances_속성에 그 값들이 저장되어있습니다.
코드는 다음과 같습니다.
print(dt.feature_importances_)
이번 포스트에서는 결정 트리의 개념을 알아보았습니다.
지니 불순도와 정보 이득의 개념을 알고 결정 트리가 어떻게 작동하는 지 알아보고
실제 코드를 통해 학습을 해봤습니다.
'Book Review > [혼공머신] 리뷰' 카테고리의 다른 글
GBM기반 앙상블: XGboost, LightGBM (0) | 2023.01.16 |
---|---|
트리 앙상블 (1) | 2023.01.16 |
확률적 경사 하강법 (2) | 2023.01.04 |
로지스틱 회귀 (0) | 2023.01.04 |
다중회귀 & 릿지, 라쏘회귀 (2) | 2022.12.08 |