본문 바로가기

머신러닝

[Machine Learning] Tree Based ML - 1. Decision Tree

Tree based Machine Learning의 기본 Decision tree.

데이터 분할하는 Algorithm으로 분류와 회귀문제 모두 적용 가능.

선형모델과 달리, Decision Tree 모델은 특성들을 기준으로 샘플을 분류해 나가는 형태.

각 특성들의 수치를 가지고 질문을 통해 정답 클래스를 찾아가는 과정, 여기서 질문이나 말단의 정답을 Node(노드)라고 하며 그 Node를 연결하는 선을 Edge(엣지)라고 한다.

 

  • 결정트리는 분류(Classifier)와 회귀(Regressor)문제 모두 적용 가능합니다.
  • 결정트리는 데이터를 분할해 가는 알고리즘입니다.
  • 분류 과정은 새로운 데이터가 특정 말단 노드에 속한다는 정보를 확인한 뒤 말단노드의 빈도가 가장 높은 범주로 데이터를 분류한다.

결정트리의 각 노드(node) 

  • ROOT Node : 뿌리노드  
  • Internal Node: 중간노드 
  • Leaf Node: external, leaf, terminal -(더이상 가지가 뻗어나갈 수 없는 단계) 말단 노드로 나뉜다.

[출처] 코드스테이츠 강의 노트

Node 를 나누는 Algorithm : 지니불순도 & 엔트로피 ; IG

결정트리의 비용함수를 정의하고 그것을 최소화 하도록 분할하는 것이 트리모델 학습 알고리즘
  • 지니불순도(Gini Impurity or Gini Index):  = 1 -( the probability of "Yes")^2 - (the probability of "No")^2 = 1 - (N(Yes)/(N(Yes)+N(No)))^2 - (N(No)/(N(Yes)+N(No)))^2

엔트로피(Entropy)는 불순도(Impurity)를 수치적으로 나타낸 척도.

엔트로피가 높다 = 불순도가 높다

엔트로피가 낮다 = 불순도가 낮다 (good)

엔트로피가 1이면 불순도가 최대. 즉, 한 범주 안에 서로 다른 데이터가 정확히 반반 있다는 뜻.

엔트로피가 0이면 불순도는 최소. 한 범주 안에 하나의 데이터만 있다는 뜻입니다.

 

엔트로피를 구하는 공식은 아래와 같다.

  • 엔트로피(Entropy): H =∑(사건발생확률)⋅log2(1/사건발생확률)=∑i(pi) log2(1/pi)=−∑i(pi) log2(pi)

 

Information Gain ; IG

  • 특정 속성을 기준으로 Example들을 구분하게 될때 '감소되는 Entrophy의 양'
  • 정보획득(Information Gain)은 특정한 특성을 사용해 분할했을 때 엔트로피의 감소량
  • IG(T,a) = H(T) - H(T|a) = 분할전 노드 불순도 - 분할 후 자식노드 들의 불순도 = entropy(parent) - [weighted average] entropy(children)
  • IG는 클수록 좋다. 

 

 

 

 

가지치기(Pruning)

Decision Tree는 특성상 과적합이 잘 일어남, 이를 줄이기 위해 복잡도를 낮춰야 한다.  복잡도를 낮추는것을 Pruning(가지치기)라고 한다. 아래의 HyperParameter 조절

  1. min_sample_leaf
  2. min_sample_split (min_sample_split = 10이면 한 노드에 10개의 데이터가 있다면 그 노드는 더 이상 분기를 하지 않습니다.)
  3. max_depth (max_depth = 4이면, 깊이가 4보다 크게 가지를 치지 않습니다.)

 즉, 최대 깊이(max_depth)나 터미널 노드의 최대 개수(min_sample_leaf), 혹은 한 노드가 분할하기 위한 최소 데이터 수(min_sample_split )를 제한하는 것.

 

Decision Tree Process

Yes or No data (이진분류문제일때) Numeric Data (회귀문제일때)
Gini Impurity 값을 모두 계산 Numeric data를 순서대로 정령
노드 자체의 값이 가장 낮으면 더이상 가지치기를 하지않고 Leaf node로 남는다 인접한 모든 numeric data를 평균내어 계싼
데이터 분리가 개선되면 Gini Impurity값이 가장 낮은 항목의 데이터 분리를 실행 각 평균값들의 Impurity values계산

[출처] 코드스테이츠 강의노트

Python - Decision tree classifier

1. 라이브러리 불러오기

from sklearn.tree import DecisionTreeClassifier
from category_encoders import OneHotEncoder
from sklearn.impute import SimpleImputer
from sklearn.pipeline import make_pipeline

2. 파이프라인을 이용하여 Decision Tress Classifier

결정트리에서는 StandardScaler는 도움이 되지 않기 때문에 제외하고 학습

pipe = make_pipeline(
    OneHotEncoder(use_cat_names=True),  
    SimpleImputer(), 
    DecisionTreeClassifier(random_state=1, criterion='entropy'))

pipe.fit(X_train, y_train)
print('훈련 정확도: ', pipe.score(X_train, y_train))
print('검증 정확도: ', pipe.score(X_val, y_val))
훈련 정확도:  0.9908667674880646
검증 정확도:  0.7572055509429486

>>>>> 훈련정확도 99%라는 과접합이 발생.

3. 검증값으로 훈련 정혹도와 다른점 확인하기

y_val.value_counts(normalize=True)
0    0.761001
1    0.238999
Name: vacc_h1n1_f, dtype: float64

4. 과적합 해결을 위한 하이퍼 파라미터 사용

1) 말단 노드(external node)에 최소한 존재해야 하는 샘플들의 수 지정

pipe = make_pipeline(
    OneHotEncoder(use_cat_names=True), 
    SimpleImputer(), 
    DecisionTreeClassifier(min_samples_leaf=10, random_state=2))

pipe.fit(X_train, y_train)
print('훈련 정확도', pipe.score(X_train, y_train))
print('검증 정확도', pipe.score(X_val, y_val))

훈련 정확도 0.8577528689618361

검증 정확도 0.8029889692800379

 

2)max_depth 제한

pipe = make_pipeline(
    OneHotEncoder(use_cat_names=True), 
    SimpleImputer(), 
    DecisionTreeClassifier(max_depth=6, random_state=2)
)

pipe.fit(X_train, y_train)
print('훈련 정확도', pipe.score(X_train, y_train))
print('검증 정확도', pipe.score(X_val, y_val))

훈련 정확도 0.8283367434688491

검증 정확도 0.8269481674771676

 

3) GridSearchCV / RandomizedSearchCV 이용 최적의 하이퍼파라미터 지정

  • GridSearchCV: 검증하고 싶은 하이퍼파라미터들의 수치를 정해주고 그 조합을 모두 검증합니다.
  • RandomizedSearchCV: 검증하려는 하이퍼파라미터들의 값 범위를 지정해주면 무작위로 값을 지정해 그 조합을 모두 검증합니다.

5. Feature Importance 특성 중요도

선형모델에서는 특성과 타겟의 관계를 확인하기 위해 회귀 계수(coefficients)를 살펴보지만 결정트리에서는 대신 특성중요도를 확인한다.
회귀계수와 달리 특성중요도는 항상 양수값을 가지며. 이 값을 통해 특성이 얼마나 일찍 그리고 자주 분기에 사용되는지 결정된다.
model_dt = pipe.named_steps['decisiontreeclassifier'] # 파이프라인에서 스텝 가지고 나오기

importances = pd.Series(model_dt.feature_importances_, encoded_columns) # 중요특성 따로 데이터프레임으로 만들어주기
plt.figure(figsize=(10,30)) # 그래프로 만들기
importances.sort_values().plot.barh();

[출처] 코드스테이츠

 

6. 최종 모델 학습 

위의특성중요도를 반영한 데이터 features와 최적의 하이퍼파라미터를 적용시킨 모델을 test set에 학습시킨다.

 

7. 트리모델 시각화 하기

1) graphviz 모듈 설치 및 라이브러리 불러오기

# graphviz 설치방법: conda install -c conda-forge python-graphviz
import graphviz
from sklearn.tree import export_graphviz

2) 파이프라인에서 모델과 인코더 추출하여 그래프 데이터셋 만들고 시각화.

model_dt = pipe.named_steps['decisiontreeclassifier']
enc = pipe.named_steps['onehotencoder']
encoded_columns = enc.transform(X_val).columns

dot_data = export_graphviz(model_dt
                          , max_depth=3
                          , feature_names=encoded_columns
                          , class_names=['no', 'yes']
                          , filled=True
                          , proportion=True)


display(graphviz.Source(dot_data))

Python- Decision tree Regressor

1. 라이브러리 불러오기

from ipywidgets import interact
from sklearn.tree import DecisionTreeRegressor, export_graphviz

2. 인터랙션함수에 모델 대입 및 학습

def thurber_tree(max_depth=1):
    tree = DecisionTreeRegressor(max_depth=max_depth)
    tree.fit(X_thurber, y_thurber)
    print('R2: ', tree.score(X_thurber, y_thurber))
    ax = thurber.plot('mobility', 'density', kind='scatter', title='Thuber')
    ax.step(X_thurber, tree.predict(X_thurber), where='mid')
    plt.show()
    display(show_tree(tree, colnames=['mobility']))

interact(thurber_tree, max_depth=(1,6,1));

max_depth = 1인 경우는 선형회귀 보다 성능이 안 좋아 보이지만 max_depth를 더할 수록 선에 적합이 되어 비선형 데이터를 학습할 수 있음을 시각적으로 확인할 수 있다. 

 

 

특성 상호작용

결정트리모델은 선형모델과 달리 비선형, 비단조(non-monotonic), 특성상호작용(feature interactions) 특징을 가지고 있는 데이터 분석에 용의합니다.

  • 특성상호작용
    • 특성상호작용은 특성들끼리 서로 상호작용을 하는 경우를 말합니다. 회귀분석에서는 서로 상호작용이 높은 특성들이 있으면 개별 계수를 해석하는데 어려움이 있고 학습이 올바르게 되지 않을 수 있습니다. 하지만 트리모델은 이런 상호작용을 자동으로 걸러내는 특징이 있습니다