상세 컨텐츠

본문 제목

[머신러닝 커닝 페이퍼] 분류를 위한 결정트리모델의 모든 것 1편

프로그래밍/Data&ML

by 척척석사 민준 2022. 12. 1. 18:54

본문

728x90
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# 학습데이터와 테스트데이터 나눠준다
X_train, X_test, y_train, y_test = train_test_split(data, label, test_size = 0.2, random_state=0)

# 결정트리 모델 학습
dt_clf = DecisionTreeClassifier(random_state=0)
#dt_clf = DecisionTreeClassifier(random_state=0, min_samples_split = 3, max_depth = 3)
dt_clf.fit(X_train, y_train)
dt_pred = dt_clf.predict(X_test)

# 모델 평가
accuracy = accuracy_score(y_test, dt_pred)*100
print("정확도 : ", "%.1f"%accuracy + '%')

# 주요 피처별 중요도 시각화
import seaborn as sns

importance_value = dt_clf.feature_importances_
importance_value = pd.Series(importance_value, index=X_train.columns)
top20 = importance_value.sort_values(ascending=False)[:20]

plt.title('Important Features Top 20')
sns.barplot(x= top20, y=top20.index)
print(top20)

# 전체 트리 시각화
from sklearn import tree
import graphviz

tree_dot = tree.export_graphviz(dt_clf, feature_names = data.columns, class_names = ['A', 'B', 'C'], filled= True)
dt_graph = graphviz.Source(tree_dot, format='png')
dt_graph

코드 설명

사이킷런은 똑똑하고 배려심 깊은 분들이 만든 분석 툴이기 때문에 한 번만 사용해보면 누구나 쉽게 다양한 알고리즘을 이용해 머신러닝을 시험해 볼 수 있다. (떠먹여 줘도 못 먹으면 문제가 있다)

 

1단계 : 변수에 모델을 지정해준다.

random_state는 그냥 학습할때 알고리즘 내부적으로 데이터를 랜덤 하게 섞는데 성능평가를 위해 동일하게 섞으라고 0으로 지정해준다(아무 숫자나 해도 괜찮다)

dt_clf = DecisionTreeClassifier(random_state = 0)

만약 가지치기를 위한 파라미터를 설정하려면 지금 해야한다.

df_clf = DecisionTreeClassifier(random_state = 0 , min_samples_split = 3, max_depth = 3)

 

2단계 : fit 함수를 통해 학습을 시켜준다

dt_clf.fit(X_train, y_train)

fit 함수는 자기 자신을 반환하기 때문에 다른 함수랑 메서드 연결을 할 수 있다.

2022.12.01 - [자연과학도를 위한 프로그래밍 (Python+MATLAB)/머신러닝과 데이터분석 (Python)] - [머신러닝 컨닝 페이퍼] 메서드 연결 y_pred = dt_clf(X_train, y_train).predict(X_test)

 

3단계 : predict 함수를 통해 테스트 데이터로 시험을 본다 (값을 예측)

시험 결과를 dt_pred에 저장해준다.

dt_pred = dt_clf.predict(X_test)

 

4단계 : accuracy_score 함수로 시험 결과를 채점해본다

accuracy = accuracy_score(y_test, df_pred)*100

100을 곱해준 건 백분율로 보기 위해서이다. (왜 그런지 모르겠지만 다른 책에서는 0.88 이런 식으로 소수점으로 계산하는데 이게 정석인 거 같다.)

 

시각화 : feature_importances_ 메서드를 이용한 주요 피쳐 찾기

dt_clf.feature_importances_ 를 통해 분류에 영향을 주는 주요 피쳐들을 얻을 수 있다.

 

시각화 : Graphviz를 이용한 결정 트리 시각화

(Colab에서는 작동한 코드인데 개발환경에 따라 다를 수 있다)

class_names = ['A', 'B', 'C']는 다른 곳에서는 class_names = data.feature_name이라고 하던데 나는 직접 만든 데이터 셋이라 그런 걸 만들지 않아서 그냥 0, 1, 2로 분류되어있는 데이터를 순서대로 'A' , 'B', 'C'로 지정했다.

만약 0, 1로 분류되어있으면 ['A', 'B'] 이런 식으로 바꾸면 된다.

 

from sklearn import tree
import graphviz

tree_dot = tree.export_graphviz(dt_clf, feature_names = data.columns, class_names = ['A', 'B', 'C'], 

filled= True)
dt_graph = graphviz.Source(tree_dot, format='png')
dt_graph

 

결정 트리 모델에서 제일 중요한 건 내 생각엔 시각화이다.

다른 머신러닝 모델은 사람이 해석하기가 힘들다. 

(딥러닝의 경우 수백 개의 노드와 가중치 그리고 미분계수들로 이어져있는데 이걸 이해할 수 있는 사람이 있을까...)

근데 결정 트리 모델만은 모델의 결과를 사람이 해석할 수 있는 직관적인 모델이다. (직관적이고 결정 방식을 이해하기 쉬운 이런 모델을 화이트박스 모델이라고 하고, 결정방식을 설명하기 힘든 모델을 블랙박스 모델이라고 한다.)

분류 노드에선 어떤 인자가 들어가는지, 어떤 피쳐가 분류에 중요한 기준이 되는지(feature_importances_)를 모두 시각화할 수 있다.

다른 모델과는 다르게 해석할 수 있다는 가장 큰 장점이 있는데 당연히 이용해야지!

특히 분석하는 사람이 데이터셋에 대해서 잘 이해하고 있으면 역으로 데이터셋에 어떤 문제가 있는 건가? 역으로 추적해볼 수도 있다.

 

결정트리 시각화

 

해석하기도 쉽고 적용도 쉽지만 트리 모델의 가장 큰 단점은 쉽게 과대 적합된다는 점이다.

다른 말로는 트리 모델은 일반화된 모델을 만들기가 힘들다.

즉 노이즈에 매우 취약하고 분류 범위 밖의 데이터를 처리하지 못한다.

근본적인 이유는 트리 모델이 CART 알고리즘을 사용하기 때문이다.

CART 알고리즘은 탐욕적인 알고리즘(greedy algorithm)이라고 불리는데 원하는 분류를 만들 때까지 끝없이 분류작업을 하기 때문에 정확도 100%도 가능한 알고리즘이다. 정확도도 높고 해석도 쉽고 SImple is the best라는 격언도 있지 않은가?

결정 트리 모델만 쓰면 되지 다른 복잡한 알고리즘은 왜 사용할까?

CART 알고리즘에는 태생적인 한계가 있다...

오렐리앙 제롱에 따르면 CART 알고리즘으로 최적의 트리를 찾는 건 NP-완전 문제이기 때문에 다항 시간 안에 이 문제를 풀 수 없다는 수학적 난제에 부딪히게 된다. 자세한 내용은 잘 모르지만 결정 트리 모델로는 최적의 답을 찾을 수는 없다.

만족할만한 답, 설명이 가능한 답을 얻는 것이 결정 트리 모델을 사용하는 의의라고 할 수 있다.

 

이런 단점을 보완하기 위해 파라미터 규칙을 정해서 원하는 가지만을 뻗도록 가지치기를 해준다.

(CART 알고리즘이 계속해서 답을 찾기 위해 데이터를 먹어치우기 전에 멈춰!라고 해주는 것이다)

가지치기란 말 그대로 잘못 뻗은 가지를 잘라서 보다 일반화된 모델을 만드는 과정이다.

애초에 가지가 일정 수준 이상으로 뻗지 못하도록 하는 사전 가지치기와 만들어진 모델에서 통계적 모델을 사용해 가지를 치는 사후 가지치기 방법이 있다.

 

사전 가지치기를 위한 파라미터

- min_samples_split : 노드 분할을 위한 최소한의 데이터 수, 작을수록 과적합이 된다. (1이면 오차 데이터 하나만으로도 가지가 생기게 된다. 기본값은 2)

- min_samples_leaf : 노드 분할이 이뤄진 이후 각가지에서 가지고 있는 데이터 개수의 최솟값, 작을수록 과적합이 된다. (단 데이터가 불균일한 경우 분류자체가 수행되지 않으므로.. 데이터가 불균일한 경우는 작게 설정해준다)

- max_depth : 트리의 최대 깊이를 규정해준다. 

사이킷런 핵심 개발자이신 "안드레아스 뮐러"와 "세라 가이도"에 따르면 사전 가지치기 방법 중 max_depth, max_leaf_nodes 또는 min_samples_leaf 중 하나만 지정해도 과대 적합을 막는 데 충분하다.

 

사후 가지치기를 위한 파라미터

- ccp_alpha 매개변수 : DecisionTreeClassifier(ccp_alpha = 0.002) 이런 식으로 알파를 변화시키며 정확도를 교정할 수 있다.

 

GridSearchCV를 이용하면 여러 파라미터를 변화시키면서 최적화를 할 수 있다.

 

결정 트리 모델은 다른 모델들의 토대가 되는 모델이기도 하다.

이진 분류라는 큰 틀을 가지고 노드 분할기준, 손실 함수, 가지치기 알고리즘 등을 변화시킨 다양한 모델이 있다.

 

<사이킷런에 구현되어 있는 트리 기반 앙상블 모델들>

1. 랜덤 포레스트 RandomForestClassifier

2. 그레이디언트 부스팅 GradientBoostingClassifier

3. 배깅 BaggingClassifier

4. 엑스트라 트리 ExtraTreesClassifier

5. 에이다 부스트 AdaBoostClassifier

6. 히스토그램 기반 부스팅 HistGradientBoostingClassifier

 


참고자료

어디선가 들은 강의와 유튜브와 내 생각들..

<파이썬 머신러닝 완벽 가이드 : 김철민>

<파이썬 라이브러리를 활용한 머신러닝 : 안드레아스 뮐러, 세라 가이도>

<핸즈온 머신러닝 : 오렐리랑 제롱>

 

 

 

728x90

관련글 더보기