<알고가야하는 키워드>
기존의 로지스틱 회귀를 통해서 분류를 하는 방정식을 구했다면, 이걸 다른 사람에게 어떻게 설명 해야 할까?
(length에 1.27을 곱하고, weight에 -9.74를 곱해서 나오는 수가 0보다크면 빙어, 작으면 농어 입니다~~)
-->이 방정식 구조는 사람이 이해하기 힘들고, 모델이 복잡한 계산을 통해서 도출한 법칙에 해당 됨
결정트리(Decision tree): 스무고개 질의응답처럼, 질문을 하나씩 던져가면서 정답을 맞추어 나가는 형태 (당도가 2보다 작은가요? 예(레드와인), 아니오(화이트와인) 이렇게 질문을 던져나가면서 분류가 가능함)
예/아니오에 대한 질문을 이어나가면서 정답을 찾아 학습하는 알고리즘이다. 비교적 예측 과정을 이해하기 쉽고 성능이 뛰어나다. 또한 데이터 스케일 전처리를 할 필요가 없다는 장점도 있다.
그림을 그릴수도 있으며, 왼쪽방향이 Yes, 오른쪽 방향이 No 대답을 한 방향이다.
지니 불순도(gini impurity): DecisionTreeClassifier 클래스의 criterion 매개변수는 데이털르 분할하는 기준을 정하는 매개변수 이다. 이때 지니 불순도 감소량을 최대화 하는 방향으로 선택한다.(불순도는 0~1사이의 값을 가지며, 클수록 분류가 잘 안된것이다.(안좋은거임))
지니불순도 계산법: 1-(음성클래스 개수/전체클래스 개수)^2 - (양성클래스 개수/전체클래스 개수)^2
== 1-음수클래스비율^2 -양성클래스비율^2
정보 이득(information gain): 부모노드와 자식노드들의 불순도 차이를 의미함, 정보 이득이 최대가 되어야지 좋은 결정트리 알고리즘 이다.
정보 이득 계산식: 부모노드불순도-왼쪽자식노드불순도*(왼쪽자식샘플개수/부모샘플개수)- 오른쪽자식노드불순도*(오른쪽자식샘플개수/부모샘플개수)
불순도를 계산할때 criterion = 'entropy'로 변경하면 엔트로피 불순도로 사용할수 있다. 계산식은 다음과 같다.
-음성클래스비율*log2(음성클래스비율) - 양성클래스비율*log2(양성클래스비율)
하지만 지니 불순도와 엔트로피 불순도가 만든 결과의 차이는 크지 않기에 지니 불순도를 기본으로 사욯한다.
노드를 순수하게 잘 나눌수록 정보이득이 커지는걸 기억하자
가지치기: 무작정 끝없이 자라나는 트리가 될수도 있다.(훈련세트는 아주 잘 맞지만 테스트 세트에서는 좋은 성능을 보이지 못함, 과적합의 위험, 이를 일반화가 잘 안되었다고 함), max_depth 매개변수를 활용하여 깊이제한이 가능하다.
특성중요도: 결정트리에 사용된 특성이 불순도를 감소하는데 큰 기여를 한 정도, 특성 중요도를 계산가능한것이 결정트리의 또다른 큰 장점이다.
<유용한 코드>
df.info() # 각 colum의 데이터타입과 누락된 데이터가 있는지 확인
df.describe() # colum에 대한 통계값(개수, 평균, 표준편차, 최소값, 1사분위수, 2사분위수(중앙값), 3사분위수, 최대값)
print(wine['class'].unique()) # [0. 1.] 0이면 레드 와인, 1이면 화이트 와인
# 예측하기
new_sample = np.array([[10, 3, 3.5]])
new_sample_scaled = ss.transform(new_sample)
prediction = lr.predict(new_sample_scaled)
print("예측 결과:", prediction) # 레드와인에 속함
# 트리 그림 그리기(전처리 안한 데이터로)
import matplotlib.pyplot as plt
from sklearn.tree import plot_tree
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.savefig('가지치기와전처리X한_트리그림.png')
print(dt.feature_importances_) # 특성 중요도 출력
전체코드는 아래와 같다
#%%
import pandas as pd
wine = pd.read_csv('https://bit.ly/wine_csv_data')
print(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
'''
print(wine['class'].unique()) # [0. 1.] 0이면 레드 와인, 1이면 화이트 와인
print(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 (1사분위수)
50% 10.300000 3.000000 3.210000 1.000000 (2사분위수, 중앙값)
75% 11.300000 8.100000 3.320000 1.000000 (3사분위수)
max 14.900000 65.800000 4.010000 1.000000 (최대값)
'''
#%% -------- 데이터 준비 시작
data = wine[['alcohol','sugar','pH']].to_numpy()
print(data)
target = wine['class'].to_numpy()
from sklearn.model_selection import train_test_split
# 8:2 비율로 트레인 테스트 설정
train_input, test_input, train_target, test_target = train_test_split(data, target, test_size=0.2, random_state=42)
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
ss.fit(train_input)
train_input_scaled = ss.transform(train_input)
test_input_scaled = ss.transform(test_input)
#%%
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression()
lr.fit(train_input_scaled, train_target)
print(lr.score(train_input_scaled, train_target)) # 0.7808350971714451
print(lr.score(test_input_scaled, test_target)) # 0.7776923076923077
print(lr.coef_, lr.intercept_)
# %% 예측해보기
import numpy as np
# 샘플 데이터
new_sample = np.array([[10, 3, 3.5]])
# 표준화
new_sample_scaled = ss.transform(new_sample)
# 예측
prediction = lr.predict(new_sample_scaled)
print("예측 결과:", prediction) # 레드와인에 속함
# %% 결정트리 구조를 활용(모델이 왜 그런 기준으로 분류했는지 이유를 설명하기가 쉽다!)
from sklearn.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier(random_state=42) # 최적의 분할을 찾기 위해 보통은 특성의 순서를 섞는다
dt.fit(train_input_scaled, train_target)
print(dt.score(train_input_scaled, train_target)) # 0.996921300750433
print(dt.score(test_input_scaled, test_target)) # 0.8592307692307692
# 위는 과대적합된 모델임'
# %% 결정트리를 이해하기 쉬운 그림으로 나타내는 법
import matplotlib.pyplot as plt
from sklearn.tree import plot_tree
plt.figure(figsize=(10,7))
#plot_tree(dt)
#plt.savefig('결정트리.png')
# (결정트리모델, 최대깊이제한, 클래스 비율에 따른 색칠하기, 특성의 이름을 전달해서 사람이 쉽게 보게 하기)
plot_tree(dt, max_depth=2, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.savefig('결정트리깊이제한.png')
# 왼쪽이 해당 조건에 Yes 대답, 오른쪽이 No 대답 이다.
#%% 가지치기를 실행하자
dt = DecisionTreeClassifier(max_depth=3, random_state=42) # 최대 깊이를 지정함
dt.fit(train_input_scaled, train_target)
print(dt.score(train_input_scaled, train_target)) # 0.8454877814123533
print(dt.score(test_input_scaled, test_target)) # 0.8415384615384616
plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.savefig('3까지_가지치기.png')
#%% 데이터 스케일 전처리 하기전 데이터를 사용하면, 명확하게 기준을 알수 있다.
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.savefig('가지치기와전처리X한_트리그림.png')
print(dt.feature_importances_) # 특성 중요도 출력
'머신러닝 & 딥러닝' 카테고리의 다른 글
[혼자 공부하는 머신러닝] 05-02 교차검증과 그리드 서치 (0) | 2024.02.11 |
---|---|
[혼자 공부하는 머신러닝] 04-02 확률적 경사하강법(SDGClassifier) (0) | 2024.02.03 |
[혼자 공부하는 머신러닝] 04-01 로지스틱 회귀 (0) | 2024.01.28 |
[혼자 공부하는 머신러닝] 03-03 특성공학과 규제(다중회귀, 변환기, 릿지&라쏘 회귀) (1) | 2024.01.24 |
[혼자 공부하는 머신러닝] 03-2 선형회귀 그리고 다항회귀 (0) | 2024.01.21 |