AI/혼자공부하는머신러닝딥러닝

[ML] 05-1 결정 트리

inthyes 2024. 1. 22. 02:32

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

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

 

데이터셋을 판다스 데이터프레임으로 제대로 읽어 들였는지 head() 메서드를 통해 처음 5개의 샘플을 확인한다.

wine.head()

 

판다스 데이터프레임의 info()메서드는 데이터프레임의 각 열의 데이터 타입과 누락된 데이터 확인에 유용하다.

wine.info()

describe()메서드는 열에 대한 간략한 통계를 출력한다.

이 메서드는 평균, 표준편차, 최소, 최대 등의 값을 보여준다.

wine.describe()

위 통계를 통해 알코올 도수와 당도, pH값의 스케일이 다르다는 것을 확인할 수 있다.

 

표준화를 하기 전, 판다스 데이터 프레임을 넘파이 배열로 변환하고 훈련, 테스트 세트를 나누는 작업을 수행해야 한다.

data = wine[['alcohol','sugar','pH']].to_numpy()
target = wine['class'].to_numpy()

 

train_test_split()함수는 설정값을 지정하지 않을 경우 25%를 테스트 세트로 지정한다.

샘플 개수는 test_size에 값을 설정하여 변경할 수 있다.

from sklearn.model_selection import train_test_split
train_input, test_input, train_target, test_target = train_test_split(data, target, random_state = 42, test_size = 0.2)
print(train_input.shape, test_input.shape)

 

StandardScaler 클래스를 사용해 훈련 세트를 전처리한다.

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))

학습, 테스트 점수 모두 낮으니 모델이 과소적합함을 판단할 수 있다.

 

결정트리

결정 트리는 예/아니오에 대한 질문을 이어나가면서 정답을 찾아 학습하는 알고리즘이다.

비교적 예측 과정을 이해하기 쉽고 성능이 뛰어나다는 장점을 갖는다.

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))

 훈련 세트에 대한 점수가 높지만 테스트 세트의 성능은 그에 비해 낮기 때문에 이 모델은 과대적합이라고 판단된다.

 

결정 트리 모델 객체를 plot_tree() 함수에 전달해서 모델을 그림으로 표현할 수 있다.

import matplotlib.pyplot as plt
from sklearn.tree import plot_tree

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

맨 위의 노드를 루트 노드, 맨 아래의 노드를 리프 노드라고 칭한다.

 

max_depth 매개변수를 설정하여 트리의 깊이를 제한할 수 있다.

feature_names 매개변수에 특성의 이름을 전달하여 트리를 다시 시각화한다면 아래와 같다.

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

박스 내부는 테스트조건(sugar), 불순도(gini), 총 샘플 수(samples), 클래스별 샘플 수(value)로 이루어져 있다.

 

정보이득이란 부모와 자식노드 사이의 불순도 차이를 말한다.

결정 트리 모델은 부모 노드와 자식 노드의 불순도 차이가 가능한 크도록 트리를 성장시키는 방식을 지닌다.

 

불순도는 결정 트리가 최적의 질문을 찾기 위한 기준이다. 사이킷런은 지니 불순도와 엔트로피 불순도를 제공한다.

 

가지치기

가지치기는 결정 트리의 성장을 제한하는 방법이다. 사이킷런의 결정 트리 알고리즘은 여러 가지 가지치기 매개변수를 제공한다.

 

가지치기를 하는 가장 간단한 방법은 자라날 수 있는 트리의 최대 깊이를 지정하는 것이다.

DecisionTreeClassifier 클래스의 max_depth 매개변수를 3으로 지정하여 모델을 생성하면 루트 노드 아래로 최대 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))

 

plot_tree()함수로 트리 그래프를 그리면 아래와 같은 결과를 확인할 수 있다.

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))

plt.figure(figsize=(20, 15))
plot_tree(dt, filled = True, feature_names = ['alcohol', 'sugar', 'pH'])
plt.show()

결과를 보면 같은 트리지만, 특성값을 표준점수로 바꾸지 않았기 때문에 트리 그래프를 이해하기 더 쉽다.

당도가 1.625보다 크고 4.325보다 작은 와인 중 알코올 도수가 11.025와 같거나 작은 것이 레드와인이라는 것을 확인할 수 있다.

 

결정트리는 어떤 특성이 가장 유용한지 나타내는 특성 중요도 계산이 가능하다. 루트 노드와 깊이 1에서 당도를 사용한 것을 기반으로 당도가 가장 유용한 특성 중 하나임을 짐작할 수 있다.

이를 확인하기 위해 결정 트리 모델의 feature_importances_ 속성을 출력하면 실제로 가장 유용한 특성이 당도임을 확인할 수 있다.

print(dt.feature_importances_)