์ง๋ํ์ต ์ค์ ์์๋ธ(Ensemble)
์ ๊ธฐ๋ณธ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ์ฌ์ฉํ๋ ์ผ๋ฐ์ ์ธ ML ๋ชจ๋ธ์ ๊ฒฐ์ ํธ๋ฆฌ์ด๋ค. ์์๋ธ
์ ์์ธก์ฑ๋ฅ์ด ๋จ์ด์ง๋ ์๊ณ ๋ฆฌ์ฆ์ ๊ฒฐํฉํด ํ๋ฅ ์ ๋ณด์๊ณผ ์ค๋ฅ๊ฐ ๋ฐ์ํ ๋ถ๋ถ์ ๊ฐ์ค์น๋ฅผ ๊ณ์ ์
๋ฐ์ดํธํ๋ฉด์ ์์ธก ์ฑ๋ฅ์ ํฅ์์ํจ๋ค. ์ด์ ๊ฒฐ์ ํธ๋ฆฌ๊ฐ ์ฝํ ํ์ต๊ธฐ์ ์ ํฉํ๋ค.
ML ์๊ณ ๋ฆฌ์ฆ ์ค ์ง๊ด์ ์ผ๋ก ์ดํดํ๊ธฐ ์ฌ์ด ์๊ณ ๋ฆฌ์ฆ์ด๋ค. ์์ ๊ทธ๋ฆผ๋ง ๋ด๋(๊ฐ์ฅ ๊ฐ๋จํ ์์์ง๋ง) ์ด๋ป๊ฒ ์๊ณ ๋ฆฌ์ฆ์ด ์งํ๋๋์ง ํ๋์ ์๊ธฐ ์ฝ๋ค. ์ ๊ทธ๋ฆผ์ฒ๋ผ ๊ฒฐ์ ํธ๋ฆฌ๋ ํน์ ๊ท์น์ ๋ฐ๋ผ์ ๋ ์ด๋ธ์ ๋ถ๋ฅํ๋ ๋ชจ๋ธ์ด๋ค. ์ด ๊ท์น์ ์ด๋ค ๊ธฐ์ค์ผ๋ก ๋ง๋ค์ด์ผ ๊ฐ์ฅ ํจ์จ์ ์ธ ๋ถ๋ฅ๊ฐ ๋ ๊ฒ์ธ๊ฐ๊ฐ ์ด ๋ชจ๋ธ์ ์ฑ๋ฅ์ ์ข์ฐํ๋ค.
๋ง์ฝ ๊ท์น์ด ๋ง์์ง๊ณ ๋ชจ๋ธ์ด ๋ณต์กํด์ง๋ค๋ฉด(ํธ๋ฆฌ์ ๊น์ด๊ฐ ๊น์ด์ง๋ค๋ฉด) ๊ณผ์ ํฉ์ด ๋ฐ์ํ๊ธฐ ์ฝ๋ค.
์ํธ๋กํผ
๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๋ค. ์ํธ๋กํผ๋
์ด์ญํ์์ ๋ฐฐ์ ๋ฏ์ด ํผ์ก๋๋ฅผ ์๋ฏธํ๋ค. ๋ง์ฝ ํน์ ์งํฉ ์์ ์๋ก ๋ค๋ฅธ ๊ฐ์ด ์์ฌ ์์ผ๋ฉด ์ํธ๋กํผ๊ฐ ๋๊ณ , ์๋๋ผ๋ฉด ๋ฎ๋ค. ์ ๋ณด ์ด๋
์ 1-์ํธ๋กํผ์ด๋ค.DecisionTreeClassifier
์ ์ง๋๊ณ์๋ฅผ ์ด์ฉํ์ฌ ๋ฐ์ดํฐ ์ธํธ๋ฅผ ๋ถํ ํ๋ค.๊ท ์ผ๋
๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ์ฌ ์๊ณ ๋ฆฌ์ฆ์ด ์ฝ๊ณ ์ง๊ด์ ์ด๋ค.์๊ฐํ
๋ก๋ ํํ์ด ๊ฐ๋ฅํ๋ค.๊ท ์ผ๋
๋ง ์ ๊ฒฝ์ฐ๋ฉด ๋๋ฏ๋ก ํน๋ณํ ๊ฒฝ์ฐ๋ฅผ ์ ์ธํ๊ณ feature์ ์ค์ผ์ผ๋ง, ์ ๊ทํ ๊ฐ์ ์ ์ฒ๋ฆฌ ์์
์ด ํ์ ์๋ค. ์๋ง ์ธ์ฝ๋ฉ์ ํด์ผํ ๋ฏ.min_samples_split
๋ณด๋ค ์์์ง ๋ ๊น์ง ๊ณ์ ๋ถํ min_samples_split
์ค์ ๋๋ก ์ต๋ ๋ถํ ํ์ฌ ๊ณผ์ ํฉํ ์ ์์ผ๋ฏ๋ก ์ ๋นํ ๊ฐ์ผ๋ก ์ ์ด.๊ฒฐ์ ํธ๋ฆฌ๋ฅผ ์๊ฐํํ๊ธฐ ์ํด Graphviz๋ฅผ ์ฌ์ฉํ๋ค. ์ด ์ ํ๋ฆฌ์ผ์ด์
์ ๊ฒฐ์ ํธ๋ฆฌ ์๊ฐํ ์ธ์ Process Mining์ ํตํด ์ฐพ์ workflow๋ฅผ ๋ฐฉํฅ์ฑ ์๋ ๋คํธ์ํฌ ํํ๋ฅผ ์๊ฐํํ ์ ์๋ค.
์๋์ฐ ํ๊ฒฝ์์ ์ค์น๋ ์ข ๋ณต์กํ๋ฐ, ๋งฅ๋ถ์์๋ ์ผ๋จ ๊ฐ๋จํ๊ฒ
pip install graphviz
brew install graphviz
๋ฅผ ํตํด ์ค์นํ๋ค.
์ด์ ์ค์น๊ฐ ๋๋ฌ์ผ๋ฉด ๋ณธ๊ฒฉ์ ์ผ๋ก iris ๋ฐ์ดํฐ๋ก ์๊ฐํ๋ฅผ ํด๋ณด์!
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
import warnings
warnings.filterwarnings('ignore')
import numpy as np
import pandas as pd
dt_clf = DecisionTreeClassifier(random_state=156)
iris_data=load_iris()
x_train, x_test, y_train, y_test = train_test_split(iris_data.data, iris_data.target, test_size=0.2, random_state=11)
dt_clf.fit(x_train, y_train)
์ฐ์ iris๋ฐ์ดํฐ๋ฅผ ์์ฑํ๊ณ DecisionTreeClassifier๊ฐ์ฒด๋ฅผ ์์ฑ, ๊ทธ๋ฆฌ๊ณ ๋ฐ์ดํฐ ์ธํธ๋ฅผ train, test ์ธํธ๋ก ๋ถ๋ฆฌํ๋ค.
from sklearn.tree import export_graphviz
export_graphviz(dt_clf, out_file="tree.dot", class_names=iris_data.target_names,\
feature_names=iris_data.feature_names, impurity=True, filled=True)
export_graphviz๋ฅผ ํตํด tree.dot์ด๋ผ๋ ์ถ๋ ฅํ์ผ์ ๋ง๋ ๋ค. ๊ทธ๋ฆฌ๊ณ ์ด์ ์ด ์ถ๋ ฅํ์ผ์ ๋ถ๋ฌ์ ์๊ฐํ๋ก ๋ํ๋ด๋ฉด ๋!
import graphviz
with open("tree.dot") as f:
dot_graph = f.read()
graphviz.Source(dot_graph)
(๋งฅ ํ๋ฉด์ด ์๊ฐํ๊ฐ ์์์ ์งค๋ ธ๋ค...)
max_depth = 3
๋ก ์์ฌ๊ฒฐ์ ๋ถ๋ฅ๋ฅผ ์ฌ์ค์ ํด๋ดค๋ค.
(์์ฒญ ๊ฐ๋จํด์ก๋ค.)
์ด๋ฒ์ min_sample_split = 4
์ด๋ค.
๋ถ์ ์์๋ฅผ ์์ธํ ๋ณด๋ฉด Sample๊ฐ 3๊ฐ์ด๋ฏ๋ก ์๋ก ๋ค๋ฅธ ๊ฐ์ด ์์ด๋ ๋ถ๋ฆฌ๋์ง ์๋๋ค.
์ด๋ฒ์ min_sample_leaf = 4
์ด๋ค.
Sample์ด 4์ดํ๋ฉด ๋ฆฌํ๋
ธ๋๊ฐ ๋์ด ์ง๋๊ณ์๊ฐ ํฌ๋๋ผ๋ ๋์ด์ ๋ถ๋ฅ๊ฐ ๋์ง ์์ ๋ธ๋์น ๋
ธ๋๊ฐ ์ค์ด๋ค๊ณ ๊ฒฐ์ ํธ๋ฆฌ ๋ชจ๋ธ์ด ๊ฐ๊ฒฐํด์ง๋ค.
๊ฒฐ์ ํธ๋ฆฌ๋ ๊ท ์ผ๋์ ๊ธฐ๋ฐํด ์ด๋ ํ ์์ฑ์ ์ด๋ค ๊ท์น ์กฐ๊ฑด์ผ๋ก ์ ํํ๋๋๊ฐ ์ค์ํ๋ค. ์ค์ํ ๋ช ๊ฐ์ feature๊ฐ ๋ช
ํํ ๊ท์น ๋๋ฆฌ๋ฅผ ๋ง๋๋๋ฐ ํฌ๊ฒ ๊ธฐ์ฌํ๋ฉฐ, ๋ชจ๋ธ์ ์ข ๋ ๊ฐ๊ฒฐํ๊ณ ์ด์์น์ ๊ฐํ ๋ชจ๋ธ์ ๋ง๋ค ์ ์๋ค.
feature_importances
๋ ndarray ํํ๋ก ๊ฐ์ ๋ฐํํ๋ฉฐ feature ์์๋๋ก ๊ฐ์ด ํ ๋น๋๋ค.
import seaborn as sns
%matplotlib inline
print('Feature importances:\n{0}'.format(np.round(dt_clf.feature_importances_, 3)))
for name, value in zip(iris_data.feature_names, dt_clf.feature_importances_):
print('{0} : {1:.3f}'.format(name, value))
sns.barplot(x=dt_clf.feature_importances_, y=iris_data.feature_names)
๊ทธ๋ํ๋ฅผ ๋ณด์์ ๋ Petal length(cm)
์ด ๊ฐ์ฅ ์ค์ํ feature์ด๋ค.
์๊ฐํ๋ฅผ ํตํด ๊ฒฐ์ ํธ๋ฆฌ๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฅํ ๋ ์ผ์ผํค๋ ๊ณผ์ ํฉ์ ์ง์ ๋ด๋ณด์. ์ด๋ฒ์ ์์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ ์ฝ๋๋ฅผ ์ง๋ณด๋ ค๊ณ ํ๋ค.
from sklearn.datasets import make_classification
import matplotlib.pyplot as plt
%matplotlib inline
# ์์ ๋ฐ์ดํฐ ์์ฑ(features : 2๊ฐ, classes : 3๊ฐ์ง)
plt.title("3 Class values with 2 features Sample creation")
x_features, y_labels = make_classification(n_features=2, n_redundant=0, n_informative=2, \
n_classes=3, n_clusters_per_class=1, random_state=0)
# x์ถ์ ์ฒซ๋ฒ์งธ feature, y์ถ์ ๋๋ฒ์งธ feature๋ก ์๊ฐํ
plt.scatter(x_features[:, 0], x_features[:,1], marker='o', c=y_labels, s=25, edgecolor='k')
์ ์์์ ๋๋ค ๋ฐ์ดํฐ๋ฅผ ์์ฑํด๋ณด์๋ค. ๊ฒฐ์ ํธ๋ฆฌ์ ๊ณผ์ ํฉ์ ์์๋ณด๊ธฐ ์ํด ์ฒ์์ ํ์ดํผ ํ๋ผ๋ฏธํฐ ํ๋์์ด ์์ ๊ฒฐ์ ํธ๋ฆฌ๋ก ๋ถ๋ฅํด๋ณด์.
from sklearn.tree import DecisionTreeClassifier
dt_clf = DecisionTreeClassifier().fit(x_features, y_labels)
๊ฒฐ์ ํธ๋ฆฌ ๋ชจ๋ธ์ ํด๋น ๋ฐ์ดํฐ๋ฅผ ํ์ต์์ผฐ๋ค. ๊ทธ๋ฌ๋ฉด ์ด๋ฒ์ ๋ฑ๊ณ ์ ์๊ฐํ๋ฅผ ํตํด ์์ ๋ฐ์ดํฐ๊ฐ ์ด๋ป๊ฒ ๋ถ๋ฅ๋๋์ง ์ง์ ๋์ผ๋ก ๋ณผ๊ฒ์ด๋ค.
def visualize_boundary(model, x, y):
fig, ax = plt.subplots()
ax.scatter(x[:,0], x[:,1], c=y, s=25, cmap='rainbow', edgecolor='k',
clim=(y.min(), y.max()), zorder=3)
ax.axis('tight') # tight : ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๋ณผ ์ ์๋๋ก ์ถ์ ๋ฒ์๋ฅผ ํฌ๊ฒ ์ค์
ax.axis('off') # off : ์ถ๊ณผ ๋ผ๋ฒจ์ ๋๋ค.
xlim_start, xlim_end = ax.get_xlim() # ์ถ์ ๋ฒ์๋ฅผ ์ถ์ถ
ylim_start, ylim_end = ax.get_ylim()
model.fit(x, y)
# ๊ฒฉ์ํ๋ ฌ ์์ฑ
xx, yy = np.meshgrid(np.linspace(xlim_start, xlim_end, num=200), np.linspace(ylim_start, ylim_end, num=200))
# ๋ชจ๋ธ ์์ธก, ๊ฒฉ์ ํ๋ ฌ ์ขํ๊ฐ์ ๋ชจ๋ธ๋ก ์์ธกํ์ฌ contourf์ ๋์ด์ ํด๋นํ๋ z ๊ตฌํ๋ค.
z = model.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)
n_classes = len(np.unique(y))
# ๋ฑ๊ณ ์ ๊ทธ๋ฆฌ๊ธฐ ํจ์
contours = ax.contourf(xx, yy, z, alpha=0.3,
level=np.arange(n_classes + 1) - 0.5,
cmap='rainbow', clim=(y.min(), y.max()),
zorder=1)
visualize_boundary(dt_clf, x_features, y_labels)
ํ์ดํผ ํ๋ผ๋ฏธํฐ ํ๋์์ด ๋ถ๋ฅ ๊ฒฐ๊ณผ ์ด์์น๊น์ง ๋ถ๋ฅํ๊ธฐ ์ํด ๊ฒฐ์ ๊ธฐ์ค์ด ๋ง์์ก๋ค. ๊ฒฐ๊ตญ ๋ชจ๋ธ์ด ๋ณต์กํด์ก๋ค๋ ๊ฒฐ๊ณผ์ด๋ค. ์ด๋ฐ ๋ณต์กํ ๋ชจ๋ธ์ ํ์ต ๋ฐ์ดํฐ์ ํน์ฑ์ด ์กฐ๊ธ๋ง ๋ค๋ฅธ ๋ฐ์ดํฐ ์ธํธ๋ก ์์ธก์ ํ๋ฉด ์ ํ๋๊ฐ ๋จ์ด์ง๋ค.
์ด๋ฒ์ min_samples_leaf=6
์ผ๋ก ์ค์ ํ์ฌ ๊ธฐ์ค ๊ฒฝ๊ณ๋ฅผ ์ดํด๋ณด์.
ํ์ดํผ ํ๋ผ๋ฏธํฐ๋ฅผ ํ๋ํ๋ ์ด์์น์ ํฌ๊ฒ ๋ฐ์ํ์ง ์๋ ๊ฒ์ผ๋ก ๋ฐํ์ก๋ค. ์ด๋ฐ ๋ชจ๋ธ์ด ๋ณต์กํ ๋ชจ๋ธ๋ณด๋ค ๋ ์ฑ๋ฅ์ด ๋ฐ์ด๋๋ค.