일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 결정트리
- recall
- 평가 지표
- layer normalization
- NULLIF
- LAG
- 감정은 습관이다
- Batch Normalization
- 데이터 프로젝트
- ifnull
- 백엔드
- 강화학습
- 오차 행렬
- DecisionTree
- 데이터 분석
- sorted
- NVL
- 데이터 전처리
- nvl2
- 빠르게 실패하기
- beautifulsoup
- 지도학습
- 웹서비스 기획
- 비지도학습
- Normalization
- 재현율
- five lines challenge
- CASE WHEN
- SQL
- 정밀도
- Today
- Total
Day to_day
[지도 학습] 결정 트리(Decision Tree)의 원리와 유의점 (하이퍼 파라미터 이해, Feature importance) 본문
[지도 학습] 결정 트리(Decision Tree)의 원리와 유의점 (하이퍼 파라미터 이해, Feature importance)
m_inglet 2023. 3. 2. 01:25❗본 포스팅은 권철민 선생님의 '파이썬 머신러닝 완벽가이드' 강의와 '파이썬 라이브러리를 활용한 머신러닝' 서적을 기반으로 개인적인 정리 목적 하에 재구성하여 작성된 글입니다.
포스팅 개요
지도 학습에서 많은 전처리 없이 쉽게 다뤄볼 수 있는 모델 결정 트리(Decision Tree, 의사결정트리, 의사결정나무라고도 함)에 대해서 알아보고, 개념과 사용 예제, 트리 모델의 장단점까지 정리해보고자 한다.
결정 트리 (Decision Tree)
결정 트리의 원리는 쉽게 말하면 '스무고개' 놀이와 같이 예/아니오 질문을 이어가면서 학습하는 방식이다.
데이터를 하나의 기준에 대해 해당하는 지, 해당하지 않는 지를 분류하여 아래와 같이 트리처럼 데이터를 나누게 된다.
위의 그림은 결정 트리를 도식화 한 것이다.
각각의 네모는 '노드'를 뜻하며 맨 꼭대기. 즉 전체 데이터에 해당하는 것은 '루트 노드', 규칙이 있는 곳이 '규칙 노드', 그리고 더 이상 분할되지 않고 데이터가 균일하다고 판단되면 그 값은 '리프 노드'라고 칭한다.
데이터가 균일?
이 말이 의미하는 것을 좀 더 자세히 설명하려고 한다.
그림을 보면 첫번째는 노란색 영역 안에 있는 데이터가 섞여서 균일하지 않고, 두번째의 경우는 데이터가 섞이지 않고 파란색 데이터만 모여서 균일하다고 말할 수 있다.
이렇듯 결정 트리 과정에서 분할을 했을 때, 더 이상 다른 데이터가 섞여있지 않고 균일하게 모여있으면 분할을 멈춘다는 뜻이다.
결정 트리의 과정을 정리하면 다음과 같다.
1. 가능한 한 많은 데이터를 구분 지을 수 있는 기준을 선택 (규칙 조건)
2. 나누어진 노드의 불순도를 평가
3. 각 노드에서 하나의 규칙 조건을 가진 이진 결정 트리를 진행
4. 각 분할된 영역이 한 개의 타깃값(하나의 클래스)만 가질 때까지 위의 내용을 반복
( * 이때 하나의 클래스로만 이루어진 리프노드를 순수 노드라고 한다.)
[예제 코드]
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer
from sklearn.tree import DecisionTreeClassifier
cancer = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, stratify=cancer.target, random_state=42)
dt = DecisionTreeClassifier()
dt.fit(X_train, y_train)
accuracy_train = dt.score(X_train, y_train)
accuracy_test = dt.score(X_test, y_test)
print("Train dataset 정확도: ", accuracy_train) # 과적합이 되어 학습 데이터셋에 대해서는 100% 정답
print("Test dataset 정확도: {0:.3f}".format(accuracy_test)) # 테스트 데이터셋은 92%의 정답률
결정 트리 모델의 시각화 - Graphviz
실제 데이터를 결정 트리 모델에 적용해보았을 때 시각화 하여 트리 형식으로 보고 싶을 것이다.
그리고 시각화 했을 때 더 직관적으로 분할 과정을 알기 쉽다.
Graphviz를 이용하면 되는데 자세한 설치 방법은 다음 링크를 참고하면 된다.
시각화 예시는 다음과 같다.
첫 번째 맨 위에 있는 노드를 보자.
- 기준 : petal length ≤ 2.45
- gini 계수 : 0.667 (0에 가까울수록 균일함)
- sample : 120 (현재 규칙에 해당하는 데이터 개수)
- value = [41, 40, 39] (value 중에서 가장 큰 것을 기준으로 뚝 떼어낸다.)
- class : setosa (가장 많은 비율을 차지한 (41에 해당하는) 클래스는 setosa)
- 기준에 의해서 True, False로 나누고 다시 또 이 과정을 반복
- 조건이 붙어있으면 자식 노드를 생성한다.
- 그렇지 않고 조건이 없으면 리프 노드로 마침
그리고 주황색의 노드는 리프 노드로 gini 계수가 0인 것을 볼 수 있다.
그렇담 여기 나오는 gini 계수는 무엇인가?
정보 균일도 측정 방법
아까 말했던 데이터를 분할 했을 때 균일하다면 분할을 멈춘다고 했다. 우리는 그 균일하다는 '정도'를 알아야 한다.
그래서 두 가지가 있는데 첫 번째는 '정보 이득', 두 번째는 '지니 계수'가 있다.
정보 이득
- 엔트로피 개념을 기반으로 한다. 불확실성, 불균일성을 보는 지표이다.
- 서로 다른 값이 섞여있으면 엔트로피가 높고, 같은 값이 섞여있으면 엔트로피가 낮다. 즉, 정보 이득과 엔트로피 지수는 서로 반대의 값을 보이게 된다. 그래서 결정 트리를 분할하는 기준은 정보 이득이 높으면 분할을 멈추게 된다.
- 정보가 균일하지 않다면 엔트로피 지수는 높을 것이고, 정보 이득은 낮을 것이다.
- 정보이득 : 1 - 엔트로피 지수
지니 계수
- 경제학에서 불평등 지수를 나타낼 때 사용하는 계수
- 0이 가장 평등하고, 1로 갈수록 불평등하다.
- 머신러닝에 적용될 때는 지니 계수가 낮을수록 데이터 균일도가 높은 것으로 해석되며 계수가 낮은 속성을 기준으로 분할한다.
결정 트리의 유의점
일반적으로 트리를 만들 때 모든 리프 노드가 순수 노드가 될 때까지 진행하면, 모델이 매우 복잡해지고 훈련 데이터 셋에 과대적합된다. 그래서 과대적합을 막기 위해 여러 방법이 있다.
과대적합을 막는 방법
- 트리 생성을 일찍 중단하는 방법 (사전 가지치기)
- 트리의 최대 깊이 제한
- 리프의 최대 개수 제한
- 노드가 분할하기 위한 포인트의 최소 개수 지정
- 트리를 만든 후 처리하는 방법 (사후 가지치기)
- 데이터 포인트가 적은 노드 삭제 또는 병합
( * scikit-learn에서는 사전 가지치기만 지원)
결정 트리의 주요 하이퍼 파라미터
앞서 말했듯이 모델을 일반화시키기 위해서 결정 트리의 하이퍼 파라미터 튜닝을 통해 과대적합을 막아야 한다.
주요 하이퍼 파라미터는 다음과 같다.
- max_depth : 분할하는 횟수, 트리의 개수
- max_features : 학습할 때 모든 feature를 사용 안 해도 된다. 분할할 수 있는 규칙이 너무 많아져서 너무 tree가 커질 수 있기 때문이다.
- min_samples_split (defualt : 2) : 만약에 samples를 4라고 할 때 samples가 3개 남아있으면 더 이상 분할하지 않는다는 의미
- min_samples_leaf : 분할이 될 경우 왼쪽과 오른쪽의 브랜치 노드에서 가져야 할 최소한의 샘플 데이터 수. 만약 3이라고 하면 남아있는 샘플 데이터 수가 5개라면 어떻게 나눠도 양쪽의 노드에 최소 3개의 샘플 데이터를 줄 수가 없다. 그렇다면 분할을 중단한다.
- max_leaf_nodes : 말단 노드(leaf node)의 최대 개수
[예제 코드]
# 트리의 깊이 제한
dt_limit = DecisionTreeClassifier(max_depth=4, random_state=0)
dt_limit.fit(X_train, y_train)
print("Train dataset 정확도: {0:.3f}".format(dt_limit.score(X_train, y_train))) # train 정확도 0.988
print("Test dataset 정확도: {0:.3f}".format(dt_limit.score(X_test, y_test))) # test 정확도 0.951
결정 트리의 특성 중요도 (Feature Importance)
트리를 만드는 결정에 각 특성이 얼마나 중요한지를 평가하는 것이 특성 중요도이다.
이 값은 0-1 사이의 숫자로, 각 특성에 대해 0은 전혀 사용되지 않음을 뜻하고 1은 완벽하게 타깃 클래스를 예측했다는 뜻이다.
중요하게 알아야 할 점이 있는데 ‘어? 그러면 중요한 feature를 알았으니까 이 feature들만 가지고 분류를 하면 다 분류가 되는 건가?’ 하고 생각할 수 있는 게 그걸 의미하는 게 아니다.
단지 트리 모델에서 이진 분류를 할 때 어떤 feature가 많이 쓰이는 가를 집계해 나타내는 것이다.
어떤 특성의 feature_importance_ 값이 낮다고 해서 이 특성이 유용하지 않다는 것이 아니라 트리가 단지 그 특성을 선택하지 않았을 뿐이며 다른 특성이 동일한 정보를 지니고 있어서일 수도 있다.
특성 중요도는 항상 양수이며 특성이 어떤 클래스를 지지하는지는 알 수가 없다. 어떤 특성이 높고 낮음이 어떤 클래스를 의미하는지 알 수 없다는 말이다.
feature importance는 feature_importances_ 모듈로 접근할 수 있다.
print("특성 중요도 \n", dt_limit.feature_importances_)
결정 트리의 특성 중요도 시각화
# feature importance 시각화하기
import matplotlib.pyplot as plt
import numpy as np
def plot_feature_importances_cancer(model):
n_features = cancer.data.shape[1]
plt.barh(np.arange(n_features), model.feature_importances_, align='center')
plt.yticks(np.arange(n_features), cancer.feature_names)
plt.xlabel("feature importances")
plt.ylabel("feature")
plt.ylim(-1, n_features)
plot_feature_importances_cancer(dt_limit)
정리
결정 트리는 데이터의 스케일에 구애받지 않으므로 특성의 정규화나 표준화 같은 전처리 과정이 따로 필요 없다. 또한 스케일이 서로 다르거나 이진 특성과 연속적인 특성이 혼합되어 있을 때도 잘 작동한다.
다만, 가지치기를 적용함에도 불구하고, 과대적합되는 경향이 있어 일반화 성능이 좋지 않을 수 있다.
과대적합을 막기 위한 하이퍼 파라미터 튜닝에 더욱 신경 써야 한다.
'Machine Learning' 카테고리의 다른 글
머신러닝의 유형? 알고 넘어가기! (0) | 2023.01.18 |
---|