4장 '분류'부터가 이제 정말 머신러닝의 시작입니다.
그전까지는 머신러닝에 대한 전반적인 과정을 다뤘다면
분류를 시작으로 머신러닝의 핵심 알고리즘을 다뤄보도록 하겠습니다.
같이 시작하시죠!!
해당 내용은 '파이썬 머신러닝 완벽 가이드'를 정리한 내용입니다.
1. 분류
분류 : 학습 데이터로 주어진 데이터의 피처와 레이블 값을 머신러닝 알고리즘으로 학습해 모델을 생성하고, 새로운 데이터가 주어졌을 때 미지의 레이블 값을 예측하는 것
앞서 우리가 다뤘던 예제들이 모두 분류에 해당하는 문제들이었습니다. 분류에는 다양한 알고리즘이 존재하지만, 그중에서 정형 데이터에 대하여 가장 많이 사용하는 알고리즘이 바로 앙상블 기법입니다. 앙상블 기법은 뒤에서 더욱 자세하게 다루도록 하고 이번 시간에는 앙상블 기법의 가장 기본이 되는 '결정 트리'에 대하여 다뤄보도록 하겠습니다.
2. 결정 트리
결정 트리 : 데이터에 있는 규칙을 학습을 통해 자동으로 찾아내 트리(Tree) 기반의 분류 규칙을 만드는 것
-> 데이터의 어떤 기준을 바탕으로 규칙을 만드냐가 매우 중요!!
규칙 노드 : 규칙 조건
리프 노드 : 결정된 클래스 값
서브 트리 : 새로운 규칙이 생성될 때마다 서브트리 생성
결정 트리는 결국 '어떤 규칙을 가지고 분류를 할래?'를 결정하는 것입니다. 이는 매우 중요한 사안입니다. 분류 기준이 복잡해진다는 것은 트리의 깊이가 깊어진다는 것을 의미하고(세세하게 분류하다 보니) 이는 곧 과적합으로 이어집니다. 궁극적으로 결정 트리의 예측 성능을 떨어뜨리는 결과를 초래합니다.
2.1 결정 트리의 분류 기준
결정 트리는 정보 균일도만을 파악하여 분류를 진행합니다. 최대한 비슷한 정보들을 빠르게 분류해야 나머지를 분류하기 쉽겠죠? 정보 균일도를 판단하는데 두 가지 기준이 있습니다.
정보 이득(1-엔트로피) : 주어진 데이터 집합의 혼잡도를 의미하는 엔트로피 개념을 통해 설명
-> 데이터가 균일할수록 정보 이득이 높고, 엔트로피 지수가 낮음
지니 계수 : 원래 경제학에서 불평등을 나타낼 때 사용하는 계수로 0이 가장 평등하고 1로 갈수록 불평등해짐
-> 결정 트리는 이 지니계수가 낮은 속성을 기준으로 분할함
결정 트리는 위의 지니계수가 낮은 조건을 찾아 데이터가 모두 특정 분류로 속할 때까지 반복적으로 분할합니다.
2.2 결정 트리의 장단점
장점 : 매우 명확하고 직관적이며, 시각화로 표현이 가능하다.(Graphviz 사용)
정보의 균일도만 신경 쓰면 되기 때문에 피처의 스케일링이나 정규화 같은 사전 가공 영향을 덜 받는다.
단점 : 과적합으로 알고리즘 성능이 떨어진다. -> 앙상블 기법에서는 오히려 장점으로 작용
2.3 결정 트리 파라미터
사이킷런에서 DecisionTreeClassifier()을 통해 결정 트리 구현이 가능합니다. API의 주요 파라미터는 다음과 같습니다.
min_samples_split : 노드를 분할할 수 있는 최소한의 샘플 개수
min_ samples_leaf : leaf 노드가 되기 위한 최소한의 샘플 개수
-> min_samples_split가 6이고 min_samples_leaf가 4일 때 샘플 데이터가 (0 : 3개, 1 : 3개)라면 이는 분할 X
max_features : 최적의 분할을 위해 고려할 최대 피처 개수
max_depth : 트리의 최대 깊이
max_leaf_nodes : 말단 노드의 최대 개수
3. 결정 트리 시각화
이제 Graphviz를 사용해서 결정 트리를 시각화해보도록 하겠습니다. 시각화를 위한 데이터로는 앞서 다뤘던 붓꽃 데이터를 활용하도록 하겠습니다.
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
import warnings
warnings.filterwarnings('ignore')
# DecisionTree Classifier 생성
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)
# DecisionTreeClassifer 학습.
dt_clf.fit(X_train , y_train)
from sklearn.tree import export_graphviz
import 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)
# 위에서 생성된 tree.dot 파일을 Graphviz 읽어서 Jupyter Notebook상에서 시각화
with open("tree.dot") as f:
dot_graph = f.read()
graphviz.Source(dot_graph)
위의 사진을 보면 알 수 있듯이 Graphviz를 활용하면 분할기준, 지니계수, sample 총 수, 각 레이블마다 샘플의 개수, 분류된 레이블 등을 시각적으로 쉽게 알 수 있습니다. 또한, leaf 노드로 갈수록 색이 진해짐을 알 수 있습니다.
다음으로 결정 트리가 어떤 피처를 참고하여 분류하는지 feature_importances_라는 API를 통해 피처 별 중요도를 알 수 있습니다.
import seaborn as sns
import numpy as np
%matplotlib inline
# feature importance 추출
print("Feature importances:\n{0}".format(np.round(dt_clf.feature_importances_, 3)))
# feature별 importance 매핑
for name, value in zip(iris_data.feature_names , dt_clf.feature_importances_):
print('{0} : {1:.3f}'.format(name, value))
# feature importance를 column 별로 시각화 하기
sns.barplot(x=dt_clf.feature_importances_ , y=iris_data.feature_names)
4. 결정 트리 과적합
결정 트리는 규칙 생성 로직을 미리 제어하지 않으면 완벽하게 클래스 값을 구별해내기 위해 서브 트리를 계속 생성하기 때문에 과적합이 일어나기 매우 쉽습니다.
from sklearn.datasets import make_classification
import matplotlib.pyplot as plt
%matplotlib inline
plt.title("3 Class values with 2 Features Sample data creation")
# 2차원 시각화를 위해서 feature는 2개, 결정값 클래스는 3가지 유형의 classification 샘플 데이터 생성.
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)
# plot 형태로 2개의 feature로 2차원 좌표 시각화, 각 클래스값은 다른 색깔로 표시됨.
plt.scatter(X_features[:, 0], X_features[:, 1], marker='o', c=y_labels, s=25, cmap='rainbow', edgecolor='k')
import numpy as np
# Classifier의 Decision Boundary를 시각화 하는 함수
# 참고만 하면 됨
def visualize_boundary(model, X, y):
fig,ax = plt.subplots()
# 학습 데이타 scatter plot으로 나타내기
ax.scatter(X[:, 0], X[:, 1], c=y, s=25, cmap='rainbow', edgecolor='k',
clim=(y.min(), y.max()), zorder=3)
ax.axis('tight')
ax.axis('off')
xlim_start , xlim_end = ax.get_xlim()
ylim_start , ylim_end = ax.get_ylim()
# 호출 파라미터로 들어온 training 데이타로 model 학습 .
model.fit(X, y)
# meshgrid 형태인 모든 좌표값으로 예측 수행.
xx, yy = np.meshgrid(np.linspace(xlim_start,xlim_end, num=200),np.linspace(ylim_start,ylim_end, num=200))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)
# contourf() 를 이용하여 class boundary 를 visualization 수행.
n_classes = len(np.unique(y))
contours = ax.contourf(xx, yy, Z, alpha=0.3,
levels=np.arange(n_classes + 1) - 0.5,
cmap='rainbow', clim=(y.min(), y.max()),
zorder=1)
먼저 기본적인 파라미터로 결정 트리를 학습시켜보겠습니다.
from sklearn.tree import DecisionTreeClassifier
# 특정한 트리 생성 제약없는 결정 트리의 Decsion Boundary 시각화.
dt_clf = DecisionTreeClassifier().fit(X_features, y_labels)
visualize_boundary(dt_clf, X_features, y_labels)
이상치까지 세세하게 분류하기 위해 분류 영 영역이 매우 세세하게 나뉘어 있음을 알 수 있습니다. 이러한 상태가 바로 과적합 상태입니다. 이러한 지나친 분류는 오히려 실제 데이터에 대한 예측 성능을 떨어뜨립니다.
다음은 과적합을 방지하기 위해 min_samples_leaf = 6으로 설정한 결과입니다.
# min_samples_leaf=6 으로 트리 생성 조건을 제약한 Decision Boundary 시각화
dt_clf = DecisionTreeClassifier(min_samples_leaf=6).fit(X_features, y_labels)
visualize_boundary(dt_clf, X_features, y_labels)
이상치에 크게 반응하지 않고 일반화된 분류 규칙에 따라 분류되었음을 알 수 있습니다. 위의 결과를 보면 알 수 있듯이 결정트리에서 과적합을 방지하기 위해 적절한 제한을 주는 것은 매우 중요합니다!!
이렇게 분류에서 가장 기본이 되는
결정 트리에 대해서 자세히 살펴보았습니다.
결정 트리는 앞서 언급하였듯이 앙상블 기법의
가장 기본이 되기 때문에 매우 중요합니다.
다음 시간에는 결정 트리를 이용하여
'사용자 행동 인식' 데이터셋을 예측해보도록 하겠습니다.
사진출처
'파이썬 머신러닝 완벽가이드' 카테고리의 다른 글
4.3 앙상블 학습(보팅) (0) | 2021.11.23 |
---|---|
4.2 결정 트리 실습 - 사용자 행동 인식 데이터 세트 (0) | 2021.11.22 |
3.3 피마 인디언 당뇨병 예측 (0) | 2021.11.22 |
3.2 평가(F1 스코어, ROC와 AUC) (0) | 2021.11.21 |
3.1 평가(정밀도/재현율) (0) | 2021.11.21 |