Notice
Recent Posts
Recent Comments
Link
«   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
Tags
more
Archives
Today
Total
관리 메뉴

kang's study

9일차 : 결정트리 (Decision tree) 본문

[학습 공간]/[혼공머신러닝]

9일차 : 결정트리 (Decision tree)

보끔밥0302 2022. 3. 3. 06:21

회귀에서 MSE 성능 평가와 손실함수로 사용가능, 가중치의 함수 (미분가능)

분류에서 정확도는 성능평가, 손실함수는 로지스틱 손실함수를 사용한다.
 

결정 트리 (Decision tree)

 
새로운 분류 문제

와인 분류하기

In [26]:
import pandas as pd

wine = pd.read_csv('https://bit.ly/wine_csv_data')
In [27]:
wine.head(3)
# class는 타깃값 0이면 레드, 1이면 화이트 →  화이트 와인이 양성  
# 이진 분류 문제
Out[27]:
  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
In [28]:
wine.info() 
# data frame
# null행 빠르게 파악가능
 
<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
In [29]:
wine.describe()
Out[29]:
  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
 

데이터 준비하기

In [30]:
# 데이터 가공을 위해 넘파이 배열로 변환
data = wine[['alcohol', 'sugar', 'pH']].to_numpy()
target = wine['class'].to_numpy() 
In [31]:
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)
In [32]:
print(train_input.shape, test_input.shape)
 
(5197, 3) (1300, 3)
In [33]:
from sklearn.preprocessing import StandardScaler # 표준화 (가우시안 분포)

ss = StandardScaler()
ss.fit(train_input)

train_scaled = ss.transform(train_input)
test_scaled = ss.transform(test_input)
 

로지스틱 회귀

In [34]:
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
 

모델 설명

In [35]:
print(lr.coef_, lr.intercept_)
 
[[ 0.51270274  1.6733911  -0.68767781]] [1.81777902]
 

결정 트리 (Decision Tree)

루트 노드 : 맨 위 노드
리프 노드 : 최종 노드
In [36]:
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
In [37]:
import matplotlib.pyplot as plt
from sklearn.tree import plot_tree

plt.figure(figsize=(10,7))
plot_tree(dt)
plt.show()
 
In [38]:
# 트리 깊이를 제한 : 루트 노드와 하나의 노드만 확장 
plt.figure(figsize=(10,7))
plot_tree(dt, max_depth=1, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
# max_depth=1 루트노드 및에 한 개만 표시, 특성이름(훈련 데이터의 열 순서에 맞게 부여)
plt.show()
# vlaue  음성과 양성 개수, gini는 불순도
 
 

지니 불순도

노드에서 데이터를 분할하는 기준이다.
부모의 불순도와 자식 노드의 불순도의 차이(정보이득)가 큰 쪽으로 분할이 계속 이루어짐
불순도 기준을 이용해 정보 이득이 최대가 되도록 노드를 분할한다.
 

가지치기 (pruning)

트리의 최대 깊이를 지정해준다.
과대적합 방지
In [39]:
# 루트 노드 아래로 최대 3개 노드
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
In [40]:
plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()
# 왼쪽은 TRUE 오른쪽은 FALSE
# 레드와인은 sugar가 -0.239보다 작거나 같고 -0.802보다 크다, 알코올은 0.454보다 작거나 같아야한다.
# 결정트리는 선형함수를 훈련하는 알고리즘이 아니므로 특성의 스케일을 맞출 필요가 없다
# 당도가 음수가 되는건 어색하다 스케일을 조정할 필요가 없다.
 
 
특성값의 스케일이 결정트리 알고리즘에 영향을 주지 않는다. 따라서 표준화를 안 해도 되는 장점이 있다.
In [41]:
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
In [42]:
plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()
 
In [43]:
# 특성의 중요도
print(dt.feature_importances_) 
 
[0.12345626 0.86862934 0.0079144 ]
 
결정트리 -> 앙상블 모형 (여러 개의 결정트리로 정확도 상승)
 

가지치기 : min_impurity_decrease

노드의 정보이득 * (노드의 샘플 수)/(전체 샘플 수)가 매개변수 수치보다 작으면 분할을 멈춤

In [44]:
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
In [45]:
plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()
 

출처 : 박해선, 『혼자공부하는머신러닝+딥러닝』, 한빛미디어(2021), p220-237

Comments