본문 바로가기
Python notes/Data Science & Machine Learning

머신러닝) 의사결정나무(Decision tree)의 개념 및 실습

by 성실한 나무 2021. 9. 18.

의사결정나무(Decision tree)란 무엇인가?

 '의사결정나무'는 지도적으로 학습하는 예측적 분류/회귀 모델링 기법 중의 하나이다. 의사결정나무는 그냥 '트리'라고도 불리며, 트리를 만드는 데 사용하는 알고리즘의 이름(예: CART)으로 불리기도 한다. 이 모델은 각각의 피처(feature)들로 이루어진 트리의 노드들을 루트에서부터 차례로 살펴보고 마지막 잎 노드에 도달하면 분류 혹은 예측을 결정한다. 여기서 피처란, 데이터를 분리하는 규칙 혹은 질문을 의미한다. 이 규칙들은 데이터를 하위 영역으로 연속적으로 분할하는 것과 관련이 있다. 각 분할 혹은 분기는 어떤 한 예측변수 값을 기준으로 데이터를 위아래 두 부분으로 나누는 것이다.

 

"What is Machine Learning? Machine Learning For Beginners." from edureka!

 

  의사결정나무는 변수가 범주형(categorical)인 경우는 분류 트리, 변수가 연속형(continuous)인 경우는 회귀 트리로 구분할 수 있다. 회귀트리와 분류트리의 목적은 데이터를 작고 동질적인 그룹으로 분할하는 것이다. 그룹들의 동질성을 높이기 위한 간단한 방법은 정확도를 높이거나 오분류를 낮추는 것이다.

 하지만 불순도의 측도로 정확도를 사용하면, 샘플을 주로 한 클래스로 분류하는 방식으로 데이터를 분할하는 것보다는 오분류를 최소화하는 방식으로 데이터를 분할하는 것에 초점을 두게 되므로 잘못된 분류를 하게 될 수 있다. 이에 대한 대안이 지니 계수와 교차 엔트로피이다. 이 둘은 정확도보다는 순도에 초점을 맞춘다.

 예를 들어, CART(Classification and Regression Tree)는 불순도의 측도로 출력변수가 범주형일 경우 지니 계수를 이용하고, 연속형인 경우 분산을 이용한 이진분리를 사용한다. C4.5와 C5.0은 불순도의 측도로 엔트로피지수를 사용하고, CHAID(CHi-squared Automatic Interaction Detection)는 카이제곱 통계량을 사용한다. 일반적으로 연속형 변수를 예측하는 경우에는 편차제곱합(sum-of-squares error)을 불순도의 측도로 사용한다.

 의사결정나무는 최적화나 검색 문제에 대해서 그리디 휴리스틱(greedy heuristic)을 이용하는데, 이는 정보를 가장 많이 포함한 피처를 각 단계에서 선택하는 것이다. 다시 말하자면, 이미 알고 있는 정보를 제외하고 가장 중요한 정보를 알아낼 수 있는 질문을 고르는 것이다. 가장 중요한 정보를 알아낼 수 있는 질문이란, 결과의 불순도를 최소화할 수 있는 질문이라고 할 수 있다.

 이 모델의 장점은 다음과 같다.

  • 모델을 시각적으로 확인할 수 있어 분류 결과를 설명하기 용이하다.
  • 모델링 시 계산이 복잡하지 않아서 대용량 데이터로도 빠르게 처리할 수 있다.
  • 비정상 잡음 데이터에 대해서 민감하지 않다.
  • 다중공선성의 영향을 크게 받지 않는다.
  • 설명변수(독립변수)나 목표변수(종속변수)에 수치형변수와 범주형변수를 모두 사용 가능하다.

 반면, 이 모델은 다음과 같은 단점을 가진다.

  • 새로운 자료에 대한 과대적합이 발생할 가능성이 높다.
  • 분류 경계선 부근의 자료값에 대해서 오차가 크다.
  • 설명변수 간의 중요도를 판단하기 쉽지 않다.

 

파이썬으로 분류 트리 실습하기

 파이썬으로 분류 트리를 모델링하기 위해서 사용할 패키지는 Scikit learn, Matplotlib, 그리고 Pandas이다. Scikit learn은 다양한 통계 분석 관련 기능들을 포함하고 있다. 이 패키지의 함수들을 이용하여, 데이터셋을 훈련 데이터와 검증 데이터로 분할하고, 의사결정나무 모델링을 하고, 값을 예측하고, 모델의 성능을 평가할 수 있다. Matplotlib은 시각화 관련 기능들을 포함하고 있다. 이 패키지의 함수들을 이용하여, 의사결정나무 모델의 구조를 시각화 할 수 있고, 성능 평가 결과도 이해하기 쉬운 그래프로 그릴 수 있다. Pandas는 데이터 처리 관련 기능들을 포함하고 있다. Pandas의 DataFrame, merge 함수를 이용하면 데이터를 체계적인 RDBMS의 형태로 편집할 수 있다.

 분류 트리 실습 과정은 아래와 같다.

  • 데이터셋 준비하기
  • 분류 트리 모델링 하기
  • 모델을 시각화 하기

 실습은 Scikit learn에서 제공하는 내장 데이터셋으로 진행한다. 사용할 데이터셋은 유방암과 관련된 30개의 설명변수와 1개의 목표변수를 가지는 569행짜리 데이터셋이다. 이 데이터셋은 각 케이스 별로 설명변수의 수치값들과 해당 유방암이 양성 종양인지 악성 종양인지를 포함하고 있다. 이 분류 트리의 목표는 설명변수들의 수치값들로 유방암의 양성, 악성 여부를 분류하는 것이다.

 각 패키지들로부터 함수들을 import한 후, load_breast_cancer 함수로 유방암 데이터를 불러오고, DataFrame과 merge 함수로 데이터를 전처리 한다. 상세 코드는 아래와 같다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from sklearn.tree import DecisionTreeClassifier, plot_tree, export_text
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, precision_score, 
recall_score, f1_score, plot_roc_curve
from pandas import DataFrame, merge
from matplotlib import pyplot as plt
 
load=load_breast_cancer()
df=merge(DataFrame(load['data'], columns=load['feature_names']), 
DataFrame(load['target']).rename(columns={0:'target'}), left_index=True, right_index=True)
 
#양성(Benign)종양과 악성(Malignant)종양
for i in range(len(load['target_names'])):
    print("target %s: " %i, load['target_names'][i])
df
cs

 

 다음, train_test_split 함수를 이용하여 데이터를 훈련데이터와 검증데이터로 나눈다. 데이터는 설명변수의 훈련데이터, 설명변수의 검증데이터, 목표변수의 훈련데이터, 목표변수의 검증데이터로 나누어진다. 전체 데이터셋 중 검증데이터의 비중은 33%로 설정했다. 그리고나서 DecisionTreeClassifier 함수로 모델의 프레임(객체명: tree)을 만드는데 이 모델은 불순도의 측도가 엔트로피이고, 노드를 분할하는 기준인 최소 불순도가 0.3%이다. 이 객체에 설명변수의 훈련데이터, 목표변수의 훈련데이터를 입력하여 모델을 적합한다. 

 

1
2
3
4
5
6
7
predictors=load['feature_names']
X=df[predictors]
y=df['target']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)
 
tree=DecisionTreeClassifier(random_state=1, criterion='entropy', min_impurity_decrease=0.003)
model=tree.fit(X_train, y_train)
cs

 

 마지막으로, 분류 트리 모델을 시각화하는 방법은 두가지가 있다. 하나는 그림으로 plotting하는 것이고, 다른 하나는 text로 정리된 내용을 출력하는 것이다. 상세 코드는 아래와 같다.

 

1
2
3
4
5
6
7
8
9
10
plt.rcParams["figure.figsize"= (2020)
plt.rcParams["font.family"= 'AppleGothic'
plt.rcParams["font.size"= 16
plt.rcParams['axes.unicode_minus'= False
plt.figure()
plot_tree(model, class_names=load['target_names'], feature_names=load['feature_names'], impurity=True, filled=True, rounded=True)
plt.savefig('tree.png')
plt.show()
 
print(export_text(tree))
cs

의사결정나무 출력결과 (plot_tree & export_text) 

 

파이썬으로 분류 트리 성능 평가하기

 분류 모델의 성능을 평가하는 방법은 여러가지가 있다. 그 중에서도 보편적으로 사용되는 혼동행렬(confusion matrix)과 ROC Curve(Receiver Operating Characteristic)와 AUC(Area Underneath the Curve)로 분류 트리의 성능을 평가해 본다.

 먼저, 혼동행렬은 confusion_matrix 함수에 실제값과 예측값을 순서대로 입력함으로써 얻는다. 이 반환 값은 2차원 리스트인데 DataFrame 함수에 인덱스와 컬럼의 이름을 아래 코드와 같이 적용하면 보기 좋은 혼동행렬이 된다. 또한, 혼동행렬을 기반으로 계산하는 정밀도(precision), 민감도(specificity) 혹은 재현율(recall), F1-score도 함수로 간단하게 얻을 수 있다. 특이도(specificity)의 경우, 한번에 구할 수 있는 함수가 없지만, 직접 계산해 봄으로써 구할 수 있다. 특이도는 음성 결과를 정확히 예측하는 능력을 측정한다. 특이도를 구하는 식은 "TN / (TN+FP)"인데, 아래 혼동행렬에서 특이도를 구하자면 "61 / (61 + 6) = 0.91" 이다. 각 지표들이 90%를 넘는 것을 볼 때, 위에서 만든 분류 트리 모델의 성능은 상당히 좋다고 할 수 있다.

 

혼동행렬과 ROC Curve

 

 파이썬으로 ROC 곡선을 그리기 위해서 matplotlib의 pyplot 함수를 활용한다. plot_roc_curve의 함수에 모델 객체와 설명변수들의 값, 목표변수 값을 입력하고, pyplot의 show 함수를 통해 그래프를 확인할 수 있다. ROC 곡선의 아래 면적인 AUC가 1에 가까울 수록 성능이 좋은 분류기이다. 이 분류 트리 모델의 AUC는 0.98로 분류 성능이 매우 뛰어난 것으로 볼 수 있다.

 분류 모델을 평가하기 위한 혼동행렬, ROC Curve, AUC 등에 대한 자세한 설명은 추후 별도로 포스팅 하려고 한다.

 

 

 


[참고문헌]

막스쿤, 키엘 존슨, Applied Predictive Modeling: 실전 예측 분석 모델링 (NY: Springer, 2013), 430~431

스티븐 마슬랜드, 알고리즘 중심의 머신러닝 가이드 제2판 Machine Learning: An Algorithmic Perspective, Second Edition (경기: 제이펍, 2017), 291

윤종식, ADsP 데이터 분석 준전문가 (부산: (주)데이터에듀, 2021), 401

피터 브루스, 앤드루 브루스, 피터게데크, Practical Statistics for Data Scientists: 데이터 과학을 위한 통계 2판 (서울: 한빛미디어(주), 2021), 284~287

sklearn.tree.DecisionTreeClassifier, Scikit Learn, 2021, https://scikit-learn.org/ 

"What is Machine Learning? Machine Learning For Beginners." edureka!. last updated on Jul 15, 2021, https://www.edureka.co/blog/what-is-machine-learning/

 

댓글