Notice
Recent Posts
Recent Comments
«   2025/08   »
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 29 30
31
Archives
Today
Total
관리 메뉴

AI기록장

[ML] 결정 트리(Decision_Tree) 본문

ML/개념정리

[ML] 결정 트리(Decision_Tree)

SanL 2023. 11. 1. 16:52

결정 트리(Decision Tree)

머신러닝의 기본적인 알고리즘으로, 분류(Classification)과 회귀(Regression) 두 종류 모두 사용되는 지도학습 알고리즘.
기본적인 구조는 '예/아니요'의 방식으로 알고리즘이 전개되는데, 데이터를 다루는 목적에 따른 기준을 형성하고, 이 기준을
토대로 트리를 형성하게 된다. 앞선 기준에 따라 성능이 달라지게 된다.


트리 분기 방식

우선, 결정 트리의 알고리즘은 지니 불순도(Gini)와 엔트로피(Entropy)를 사용하여 분기하는 방식

  • 지니 불순도(Gini)
  • 집합에 있어, 이질적인 것이 얼마나 섞여 있는지 측적하는 지표이며, CART 알고리즘에서 사용
    쉽게 말해서, 어떤 집합에서 한 항목을 뽑아 무작위로 라벨을 추정할 떄 틀릴 확률을 말함
    ▹ 0에 가까워 질 수록 집합이 순수함 (데이터가 잘 분류됨)
    ▹ 1에 가까워 질 수록 집합의 이물질이 많음 (데이터 분류가 잘 이뤄지지 않음)
  • 엔트로피 (Entropy)
    혼잡도를 나타내는 개념으로, 데이터가 섞여있는 수치를 나타내주고 제대로 분류가 이뤄지지 않았다면 엔트로피가 높음

결정트리는 엔트로피(Entropy) 수치를 이용하여 정보 획드량이 가장 많은 방향으로 학습이 진행 됨.
더 자세한 과정을 알고싶다면 > 참고 블로그

장점과 단점

  • 장점
  • ▹ 결과를 해석하고 이해하기 쉬움 (간단한 정보를 빠르게 트리 시각화를 이용하여 이해가능)
    ▹ 데이터를 가공할 필요가 거의 없다. (정규화, 임의의 변수 생성 및 제거 불필요)
    ▹ 화이트박스 모델을 사용 (모델의 상황을 관측하고 결과를 확인할 수 있음)
  • 단점
  • ▹ 오버피팅의 가능성이 매우 높음
    (최적의 결가값을 찾아낼 때 까지 계속해서 분활을 진행하여, 결과를 도출
    이렇게 되면, 학습 데이터 측면에서는 좋을 수 있어도, 테스트 데이터 측면에서 안좋은 결과를 가져올 경우가 많음)

주요 파라미터

  • max_depth : 트리의 최대 깊이 규정
  • max_features : 최적의 분활을 위해 고려해야해할 피처의 개수 (디폴트는 None, 모든 피처를 고려함)
  • min_sample_split : 노드를 분활하는 과정에서 최소한의 샘플 데이터 수로 과적합을 제어하는데 사용
    (Default는 2이며, 작게 설정할 수록 노드 개수 증가로 과적합 가능성 증가)
  • min_sample_leaf : 분활 시에 오른쪽, 왼쪽 브랜치가 가져야할 최소한의 샘플 개수를 통제하는데 사용
    ( ex - 샘플이 5여도 leaf가 4이게되면 자식 노드들이 5라는 샘플을 가질 수 없음)
  • max_leaf_nodes : 말단 노드의 개수를 통제

로지스틱 회귀로 와인 분류하기

import pandas as pd

wine = pd.read_csv('https://bit.ly/wine_csv_data')

☑︎ info()를 통해 해당 Data에 null 값이나, 해당 type, memory를 확인함

항상 생각해야할 것

  • null 값을 어떻게 채울 것인가(mean, 원하느 데이터 값 etc.)
  • 원하는 데이터 결과를 도출하기 위해서, 어떤 데이터 값이 들어가 있는지, 들어가 있으면 안되는 type이 있는가
  • 전체적인 데이터의 column
wine.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6497 entries, 0 to 6496
Data columns (total 4 columns):
 #   Column   Non-Null Count  Dtype  
---  ------   --------------  -----  
 0   alcohol  6497 non-null   float64
 1   sugar    6497 non-null   float64
 2   pH       6497 non-null   float64
 3   class    6497 non-null   float64
dtypes: float64(4)
memory usage: 203.2 KB
wine.describe()
alcohol sugar pH class
count 6497.000000 6497.000000 6497.000000 6497.000000
mean 10.491801 5.443235 3.218501 0.753886
std 1.192712 4.757804 0.160787 0.430779
min 8.000000 0.600000 2.720000 0.000000
25% 9.500000 1.800000 3.110000 1.000000
50% 10.300000 3.000000 3.210000 1.000000
75% 11.300000 8.100000 3.320000 1.000000
max 14.900000 65.800000 4.010000 1.000000
wine.head()
alcohol sugar pH class
0 9.4 1.9 3.51 0.0
1 9.8 2.6 3.20 0.0
2 9.8 2.3 3.26 0.0
3 9.8 1.9 3.16 0.0
4 9.4 1.9 3.51 0.0
data = wine[['alcohol', 'sugar', 'pH']].to_numpy()
target = wine['class'].to_numpy()
from sklearn.model_selection import train_test_split

train_input, test_input, train_target, test_target = train_test_split(
    data, target, test_size=0.2, random_state=42)
print(train_input.shape, test_input.shape)
(5197, 3) (1300, 3)
from sklearn.preprocessing import StandardScaler

ss = StandardScaler()
ss.fit(train_input)

train_scaled = ss.transform(train_input)
test_scaled = ss.transform(test_input)
from sklearn.linear_model import LogisticRegression

lr = LogisticRegression()
lr.fit(train_scaled, train_target)

print(lr.score(train_scaled, train_target))
print(lr.score(test_scaled, test_target))
0.7808350971714451
0.7776923076923077

설명하기 쉬운 모델과 어려운 모델

# 특성 세개에 대한 기울기
print(lr.coef_, lr.intercept_)
[[ 0.51270274  1.6733911  -0.68767781]] [1.81777902]

-> 위 coef와 intercept를 보고 알 수 있는 것은,

알골과 당도가 높을때는, 양수가 나오므로 화이트와인

ph가 높을 수록 레드와인일 가능성이 높다.

결정 트리 Code

from sklearn.tree import DecisionTreeClassifier

dt = DecisionTreeClassifier(random_state=42)
dt.fit(train_scaled, train_target)

print(dt.score(train_scaled, train_target))
print(dt.score(test_scaled, test_target))
0.996921300750433
0.8592307692307692
import matplotlib.pyplot as plt
from sklearn.tree import plot_tree

plt.figure(figsize=(10,7))
plot_tree(dt)
plt.show()

plt.figure(figsize=(10,7))
plot_tree(dt, max_depth=1, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()

▶︎ Tree 설명

-> Sugar를 기준으로 트리를 분류하고 있으며, gini는 분순도이고, sample은 얼마나 sample을 사용하고 있느냐,

value는 위와 같은 경우 0과 1의 분포가 얼마나 있는거를 보여주고 있음

가지치기

-> 가지치기를 조절함으로써, Overfiting되는 것을 방지할 수 있음 (max_depth 조절)

dt = DecisionTreeClassifier(max_depth=3, random_state=42)
dt.fit(train_scaled, train_target)

print(dt.score(train_scaled, train_target))
print(dt.score(test_scaled, test_target))
0.8454877814123533
0.8415384615384616
plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()

dt = DecisionTreeClassifier(max_depth=3, random_state=42)
dt.fit(train_input, train_target)

print(dt.score(train_input, train_target))
print(dt.score(test_input, test_target))
0.8454877814123533
0.8415384615384616
plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()

print(dt.feature_importances_)
[0.12345626 0.86862934 0.0079144 ]

▶︎ feature importance는 피처의 중요도를 나타내는 것은 맞지만, 수치적으로 높다고해서 피처의 중요도를 1차원적으로 생각해서는 안됨

피처가 분활을하는 과정에서 얼마나 사용되고 있는지에 대한 수치화를 낸 것이기 떄문에 좀 더 생각해볼 필요성이 있음

확인 문제

dt = DecisionTreeClassifier(min_impurity_decrease=0.0005, random_state=42)
dt.fit(train_input, train_target)

print(dt.score(train_input, train_target))
print(dt.score(test_input, test_target))
0.8874350586877044
0.8615384615384616
plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()

[참고] 혼자 공부하는 머신러닝+딥러닝 , 파이썬 머신러닝 완벽 가이드