🌀 05-1 결정 트리

<aside> ❄️ 알코올, 도수, 당도, ph 값으로 레드 와인과 화이트 와인을 구별할 수 있을까? 일단 로지스틱 회귀 모형을 적용해보자!

</aside>

🐳 05-1 Code

데이터 준비

# 판다스로 6497의 와인 샘플 데이터 불러오기
import pandas as pd
wine = pd.read_csv('<https://bit.ly/wine_csv_data>')

# head 함수로 처음 5개의 데이터를 확인해본다
wine.head() #네 번째 열은 타깃값으로, 0이면 레드 와인, 1이면 화이트 와인이다.

# 판다스의 유용한 메서드 두 개 알고가기!

# info(): 각 열의 데이터 타입과 누락된 데이터가 있는지 확인하는데 유용하다.
wine.info() # non-null count가 6497이므로 누락된 값은 없다.

# describe(): 열에 대한 간략한 통계를 출력. 최소, 최대, 평균값 등
wine.describe()

<aside> ❄️ 여기에서 25%는 1사분위수, 75%는 3사분위수 이다. 사분위수는 데이터를 순서대로 4등분 한 값으로, 예를 들어 2사분위수는 데이터를 일렬로 늘어놓았을 때 정중앙의 값이다. 만약 데이터 개수가 짝수개라 중앙값을 선택할 수 없다면 가운데 2개 값의 평균을 사용한다.

</aside>

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

# 각 열의 스케일이 다르므로 특성을 표준화하자! 

# 넘파이로 바꾸기
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)
#이번에는 데이터의 개수가 많아서 테스트 세트의 개수를 20% 정도로 한정한다
#훈련세트 5197개, 테스트 세트 1300개로 분류

# 특성 표준화하하기
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))
#과소적합. 어떻게 하는 것이 좋을까?

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

# 앞서 로지스틱 모형이 학습한 계수와 절편을 출력해보자
print(lr.coef_, lr.intercept_)

# 여기에 값을 대입해 0보다 크면 화이트 와인, 작으면 레드 와인
# 시그모이드 함수애서 값이 0보다 크면 확률이 0.5 이상이므로 클래스 1(화이트 와인)
# 값이 0보다 작으면 확률이 0.5 미만이므로 클래스 0(레드 와인)

<aside> ❄️ 하지만 우리는 일반적으로 이 로지스틱 회귀 모형을 이해하기 어렵다. 계수만 보면 알코올 도수와 당도가 높을수록 화이트 와인일 가능성이 높고, ph가 높을 수록 레드 와인일 가능성이 높다. 하지만 정확히 이 숫자가 어떤 의미인지 설명하기는 어렵다. 더군다나 모델의 성능을 높이기 위해 다항 특성을 추가하면 설명하기가 더 어려워진다.

이렇게 함수 식 말고, 순서도를 그리며 화이트 와인과 레드 와인을 분류하려면 어떻게 해야 할까?

</aside>

결정 트리

# 결정 트리
# 결정 트리 모델은 스무고개와 같아서, 질문을 하나씩 던지며 정답을 맞추어가는 과정이다. 그래서 결과의 이유를 설명하기 용이하다.
# 예시: 당도가 2보다 작은가요? (네 - 레드 와인, 아니오 - 화이트 와인)
# 데이터를 잘 나눌 수 있는 질문을 찾는다면 계속 질문을 추가해서 분류 정확도를 높일 수 있다.
# 사이킷런의 DecisionTreeClassifier 을 사용한다.

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.99, 테스트 0.85 -> 과대적합

# plot_tree() 함수를 사용해 결정 트리를 이해하기 쉬운 트리 그림으로 출력해준다.

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

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

결정트리300.jpg

<aside> ❄️ 결정 트리는 위에서 아래로 거꾸로 자라난다. 맨 위의 노드는 루트 노드, 맨 아래 끝에 달린 노드를 리프 노드라고 한다.

</aside>

# 너무 복잡하니 트리의 깊이를 제한해서 출력해본다. 
# max_depth는 길이를 설정한다.
# filled 매개변수는 클래스에 맞게 노드의 색을 칠할 수 있다.
# feature_names는 특성의 이름을 전달할 수 있다.

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

# 왼쪽이 Yes(만족), 오른쪽이 No(불만족)
# filled=True로 지정하면 , 어떤 클래스의 비율이 높아지면 점점 진한 색으로 표시한다. (직관적)
# 리프 노드에서 가장 많은 클래스가 예측 클래스가 된다