import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.animation
import IPython
import sklearn.tree
#---#
import warnings
'ignore') warnings.filterwarnings(
10wk-38: 아이스크림 – 의사결정나무 원리
1. 강의영상
2. Imports
3. Data
43052)
np.random.seed(= pd.read_csv('https://raw.githubusercontent.com/guebin/DV2022/master/posts/temp.csv').iloc[:,3].to_numpy()[:100]
temp
temp.sort()= np.random.randn(100)*3 # 오차
eps = 20 + temp * 2.5 + eps
icecream_sales = pd.DataFrame({'temp':temp,'sales':icecream_sales})
df_train df_train
temp | sales | |
---|---|---|
0 | -4.1 | 10.900261 |
1 | -3.7 | 14.002524 |
2 | -3.0 | 15.928335 |
3 | -1.3 | 17.673681 |
4 | -0.5 | 19.463362 |
... | ... | ... |
95 | 12.4 | 54.926065 |
96 | 13.4 | 54.716129 |
97 | 14.7 | 56.194791 |
98 | 15.0 | 60.666163 |
99 | 15.2 | 61.561043 |
100 rows × 2 columns
4. 의사결정나무 원리
A. 분할이 정해졌을때 \(\hat{y}\)을 결정하는 방법?
-
step1~4
## step1
= df_train[['temp']]
X = df_train['sales']
y ## step2
= sklearn.tree.DecisionTreeRegressor(max_depth=1)
predictr ## step3
predictr.fit(X,y) ## step4 -- pass
# predictr.predict(X)
DecisionTreeRegressor(max_depth=1)In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
DecisionTreeRegressor(max_depth=1)
-
tree 시각화 \(\to\) 분할파악
sklearn.tree.plot_tree(predictr)
[Text(0.5, 0.75, 'x[0] <= 5.05\nsquared_error = 111.946\nsamples = 100\nvalue = 33.973'),
Text(0.25, 0.25, 'squared_error = 34.94\nsamples = 45\nvalue = 24.788'),
Text(0.75, 0.25, 'squared_error = 49.428\nsamples = 55\nvalue = 41.489')]
-
분할에 따른 \(\hat{y}\) 계산
<= 5.05].sales.mean(),df_train[df_train.temp> 5.05].sales.mean() df_train[df_train.temp
(24.787609205775055, 41.489079055828356)
B. 분할을 결정하는 방법?
-
예비학습
predictr.score(X,y)
0.6167038863844929
- 이 값이 내부적으로 어떻게 계산된거지?
predictr.score??
= y_pred = predictr.predict(X)
y_hat sklearn.metrics.r2_score(y,y_pred)
0.6167038863844929
-
좋은 분할을 판단하는 기준? – 여기에서 r2_score
가 이용됨
-
우선 논의를 편하게하기 위해서 \(({\bf X},{\bf y})\)와 경계값 \(c\)를 줄때 \(\hat{\bf y}\)을 계산해주는 함수를 구현하자.
def fit_predict(X,y,c):
= np.array(X).reshape(-1)
X = np.array(y)
y = y*0
yhat <=c] = y[X<=c].mean()
yhat[X>c] = y[X>c].mean()
yhat[Xreturn yhat
-
서로 다른 분할에 대하여 시각화를 진행
= fit_predict(X,y,c=-1)
yhat_bad = fit_predict(X,y,c=5)
yhat_good = plt.subplots(1,2)
fig, ax 0].plot(X,y,'o',alpha=0.5)
ax[0].plot(X,yhat_bad,'--.')
ax[0].set_title('bad')
ax[1].plot(X,y,'o',alpha=0.5)
ax[1].plot(X,yhat_good,'--.')
ax[1].set_title('good') ax[
Text(0.5, 1.0, 'good')
- 딱봐도 오른쪽이 좋은 분할같은데, 컴퓨터한테 이걸 어떻게 설명하지?
-
좋은분할을 구하는 이유는 좋은 yhat
을 얻기 위함이다. 그렇다면 좋은 yhat
을 얻게 해주는 분할이 좋은 분할이라 해석할 수 있다. \(\to\) 아이디어: 그런데 좋은 yhat
은 sklearn.metrics.r2_score(y,yhat)
의 값이 높지 않을까?
-
그렇다면 위의 그림에서 왼쪽보다 오른쪽이더 좋은 분할이라면 r2_score(y,yhat_good)
의 값이 r2_score(y,yhat_bad)
값보다 높을 것!
sklearn.metrics.r2_score(y,yhat_bad), sklearn.metrics.r2_score(y,yhat_good)
(0.13932141536746745, 0.6167038863844928)
-
트리의 max_depth=1
일 경우 분할을 결정하는 방법 – 노가다..
- 적당한 \(c\)를 고른다.
- 분할 \((-\infty,c), [c,\infty)\) 를 생성하고
yhat
를 계산한다. r2_score(y,yhat)
를 계산하고 기록한다.- 1-3의 과정을 무한반복 한다. 그리고
r2_score(y,yhat)
의 값을 가장 작게 만드는 \(c\)가 무엇인지 찾는다.
= np.arange(-5,15)
cuts = plt.figure()
fig def func(frame):
= fig.gca()
ax
ax.clear()'o',alpha=0.5)
ax.plot(X,y,= cuts[frame]
c = fit_predict(X,y,c)
yhat '.')
ax.plot(X,yhat,= sklearn.metrics.r2_score(y,yhat)
r2 f'c={c}, r2_score={r2:.2f}') ax.set_title(
<Figure size 672x480 with 0 Axes>
= matplotlib.animation.FuncAnimation(
ani
fig,
func,=20
frames
) display(IPython.display.HTML(ani.to_jshtml()))
-
tree가 찾은 값 5.05를 우리가 직접 찾아보자.
= np.arange(-5,15,0.05).round(2)
cuts = np.array([sklearn.metrics.r2_score(y,fit_predict(X,y,c)) for c in cuts])
score plt.plot(cuts,score)
-
방법1: 시각화로 찾는방법
'cut':cuts,'score':score})\
pd.DataFrame({='cut',y='score',backend='plotly') .plot.line(x
-
방법2: 정석
cuts[score.argmax()]
5.0
-
max_depth=2
일 경우? max_depth=1
의 결과로 발생한 2개의 조각을 각각 전체자료로 생각하고, max_depth=1
일 때의 분할방법을 반복적용한다.
-
X=[temp,type]
와 같은 경우라면? 설명변수를 하나씩 고정하여 각각 최적분할을 생성하고 r2_score관점에서 가장 우수한 설명변수를 선택