일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- NLP
- 특성중요도
- 취업부트캠프
- 취업부트캠프 5기
- 스타터스
- NLU
- 임베딩
- 데이터도서
- sql정리
- 그래프
- 부트캠프후기
- 추천시스템
- AARRR
- 서비스기획
- MatchSum
- 토스
- pytorch
- 그로스해킹
- 스타터스부트캠프
- SLASH22
- 알고리즘
- 유데미코리아
- 유데미부트캠프
- 딥러닝
- SQL
- 서비스기획부트캠프
- 사이드프로젝트
- 유데미큐레이션
- BERT
- AWS builders
- Today
- Total
다시 이음
트리 기반 모델 - 1 결정 트리 (Decision Trees) 본문
오늘은 트리기반(tree-based) 머신러닝모델에 대해서 살펴보려고 합니다.
결정트리(의사결정나무) 모델은 특성들을 기준으로 샘플을 분류해 나가는데 그 형태가 나무의 가지가 뻗어나가는 모습과 비슷해서 결정트리라는 이름을 가지고 있습니다.
결정트리의 구성
질문이나 말단의 정답을 노드(node) 라 하며 노드를 연결하는 선을 엣지(edge) 라 합니다.
결정트리의 각 노드(node)는 뿌리(root)노드, 중간(internal)노드, 말단(external, leaf, terminal) 노드로 나뉠 수 있습니다.
결정트리의 특징
- 결정트리는 분류와 회귀문제 모두 적용 가능합니다.
- 결정트리는 데이터를 분할해 가는 알고리즘입니다.
- 분류 과정은 새로운 데이터가 특정 말단 노드에 속한다는 정보를 확인한 뒤 말단노드의 빈도가 가장 높은 범주로 데이터를 분류합니다.
- 결정트리는 분류과정을 트리구조로 직관적으로 확인이 가능한 장점이 있습니다.
결정트리 학습 알고리즘
결정트리를 학습하는 것은 노드를 어떻게 분할하는가에 대한 문제입니다.
노드 분할 방법에 따라 다른 모양의 트리구조가 만들어지게 될 것입니다. 결정트리의 비용함수를 정의하고 그것을 최소화 하도록 분할하는 것이 트리모델 학습 알고리즘이 되겠습니다.
트리학습에 자주 쓰이는 비용함수 중 지니불순도와 엔트로피에 대해서 알아보겠습니다.
지니불순도(Gini Impurity or Gini Index)
지니불순도에서 불순도(impurity) 라는 개념은 여러 범주가 섞여 있는 정도를 이야기 합니다.
예를들어 A, B 두 클래스가 혼합된 데이터가 있을 때 (A, B) 비율이
- (45%, 55%)인 샘플(두 범주 수가 비슷)은 불순도가 높은 것이며
- (80%, 20%)인 샘플이 있다면 상대적으로 위의 상태보다 불순도가 낮은 것 입니다.(순수도(purity)는 높음)
불순도의 공식을 예시를 들어서 편하게 설명해볼게요.
A예시를 먼저 살펴봅시다.
위에서 설명한대로 위에있는 노드를 부모노드 혹은 루트,인터노드로 볼 수 있고 그 밑의 노드를 자식노드, 리프노드라고 볼 수 있습니다.
왼쪽의 리프노드의 지니불순도는 1 - (30/40)^2 - (10/40)^2 = 0.375 이렇게 확률의 제곱을 통해서 확인 할 수 있습니다.
똑같이 오른쪽의 리프노드의 지니불순도 1 - (10/40)^2 - (30/40)^2 = 0.375를 구할 수 있습니다.
각각 gini1(왼쪽노드 불순도) , gini2(오른쪽 노드 불순도)라고 지칭하겠습니다.
부모노드의 지니불순도는 1 - (40/80)^2 - (40/80)^2 = 0.5,
자식노드의 지니불순도 총합은 (40(왼쪽노드 개수)/80(리프노드 총 개수)*gini1 + (40(오른쪽노드 개수/80(리프노드 총 개수)*gini2 = 0.125 로 풀어쓸 수 있습니다.
하여 A예시의 정보획득량(Information Gain) 는 0.5 - 0.125 = 0.375 로 확인됩니다.
B예시를 빠르게 보면 왼쪽 리프노드는 1- (20/60)^2 - (40/60)^2 =0.4444 으로, 오른쪽 리프노드는 1 - (20/20)^2 - (0/20)^2 = 0 으로 불순도를 확인할 수 있습니다.
부모노드의 지니불순도는 1 - (60/80)^2 - (20/80)^2 = 1- 0.5625 - 0.0625 = 0.375 ,
자식노드의 지니불순도 총합은 (60/80)*gini1 + (20/80)*gini2 = 0.1666로 볼 수 있습니다.
하여 B예시의 정보획득량(Information Gain) 는 0.375 - 0.1666 = 0.2084 로 확인됩니다.
위에서 살펴본 지니불순도를 통해 어떻게 결정트리에서 노드를 분할하는가 에 대해 정리해보겠습니다.
- A예시와 B예시의 부모노드의 불순도를 비교하면 0.375, 0.2084 로 B예시가 불순도가 더 낮다고 볼 수 있음으로 B예시를 우선하여 배치하게 됩니다.
- 정보획득(Information Gain)은 특정한 특성을 사용해 분할했을 때 엔트로피의 감소량을 뜻합니다. 분할 전 부모노드 불순도 - 분할 후 자식노드 들의 불순도
- 우리는 정보획득이 최대, 부모노드의 지니불순도 - 자식노드의 지니불순도의 차이(불순도의 감소)가 최대가 되는 값을 우선으로 합니다.
- 반대로 정보획득량이 음수, 불순도의 감소가 음수로 되는 경우에는 더이상의 노드 분할이 의미없다고 판단하여 노드 분할을 그만둡니다.
사이킷런 DesicionTreeClassifier 를 사용해 결정트리를 구현
from sklearn.tree import DecisionTreeClassifier
model = DecisionTreeClassifier(random_state=2, criterion='entropy')
model.fit(X_train_scaled, y_train)
print('훈련 정확도: ', model.score(X_train_scaled, y_train))
print('검증 정확도: ', model.score(X_val_scaled, y_val))
## 파이프라인 활용하여 전처리과정과 함께 구현하기
pipe = make_pipeline(
OneHotEncoder(use_cat_names=True),
SimpleImputer(),
DecisionTreeClassifier(random_state=2, criterion='entropy')
)
pipe.fit(X_train, y_train)
print('훈련 정확도: ', pipe.score(X_train, y_train))
print('검증 정확도: ', pipe.score(X_val, y_val))
만든 결정트리를 시각화
# graphviz 설치방법: conda install -c conda-forge python-graphviz
import graphviz
from sklearn.tree import export_graphviz
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))
## 다른 방법
def show_tree(tree, colnames):
dot = export_graphviz(tree, feature_names=colnames, filled=True, rounded=True)
return graphviz.Source(dot)
결정트리의 과적합을 고쳐봅시다.
복잡한 트리는 과적합 가능성을 높이기 때문에 복잡도를 낮추어 일반화를 유도합니다.
DecisionTreeClassifier 메소드에 사용할 하이퍼 파라미터.
- min_samples_split ( 노드가 분기할 수 있는 최소한의 샘플 개수 ) : 수치가 높을 수록 과적합이 감소
- min_samples_leaf ( 말단 노드에 들어갈 수 있는 최소한의 샘플 개수 ) : 수치가 높을 수록 과적합이 감소
- max_depth ( 분할의 깊이 ) : 수치가 낮을 수록 과적합이 감소
model = DecisionTreeClassifier(min_samples_leaf=20,max_depth=8,min_samples_split=200, random_state=2, criterion='entropy')
model.fit(X_train_scaled, y_train)
print('훈련 정확도: ', model.score(X_train_scaled, y_train))
print('검증 정확도: ', model.score(X_val_scaled, y_val))
특성중요도(feature importance)
특성중요도란
마치 회귀분석에서 회귀계수와 같이 타겟과 특성의 관계를 확인할 수 있는 지표입니다.
회귀계수와 달리 특성중요도는 항상 양수값을 가집니다. 이 값을 통해 특성이 얼마나 일찍 그리고 자주 분기에 사용되는지 결정됩니다.
# 특성중요도 시각화
import matplotlib.pyplot as plt
importances = pd.Series(model.feature_importances_, X_train.columns)
plt.figure(figsize=(10,30))
importances.sort_values().plot.barh();
특성상호작용(feature interaction)
특성상호작용은 특성들끼리 서로 상호작용을 하는 경우를 말합니다.
회귀분석에서는 서로 상호작용이 높은 특성들이 있으면 개별 계수를 해석하는데 어려움이 있고 학습이 올바르게 되지 않을 수 있습니다. 하지만 트리모델은 이런 상호작용을 자동으로 걸러내는 특징이 있습니다.
예를 들어, 특성 a,b가 있을 때 a,b가 모두 해당된다면 보너스로 10000 값이 추가적으로 입력될 경우.
선형회귀분석모델은 성능이 급격하게 줄어드는 반면, 트리모델은 선형회귀모델과 달리 특성상호작용에도 문제없이 가격을 예측하는 것을 확인할 수 있습니다.
비선형 회귀문제에서 결정트리분석
max_depth 값이 낮으면 성능이 선형회귀보다 낮아보이지만 높아질수록 적합되어 학습이 가능합니다.
from ipywidgets import interact
from sklearn.tree import DecisionTreeRegressor, export_graphviz
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));
'AI 일별 공부 정리' 카테고리의 다른 글
트리 기반 모델 - 2 랜덤포레스트 (Random Forests) (0) | 2021.08.18 |
---|---|
Feature Engineering - Pipe line(파이프라인) (0) | 2021.08.18 |
회귀 분석 - 5 (Polynomial Regression) (0) | 2021.08.16 |
회귀 분석 - 4 (Logistic Regression) (0) | 2021.08.13 |
회귀 분석 - 3 (Ridge Regression) (0) | 2021.08.12 |