31. 의사결정나무(Decision Tree)
31.1 의사결정나무 모형
31.1.1 일련의 독립변수들을 활용하여 분류를 하거나 예측을 수행하는 기법
31.1.2 최종 결과물이 "일련의 규칙들"로 표현됨
31.1.3 Decision Trees 또는 Trees라고 불림
31.2 의사결정나무의 2가지 기본 아이디어
31.2.1 반복적 분할(Recursive partitioning)
31.2.1.1 레코드들을 두 부분으로 반복해서 잘라 세분된 영역 내의 동질성이 최대가 되도록 함
31.2.1.2 계속 잘라나가다 보면 모든 학습용 데이터를 100% 정확하게 분류해 낼 수 있을 만큼 세분화 해 나갈 수 있음
31.2.2 분류나무의 가지치기(Pruning the tree)
31.2.2.1 앞서 설명한 반복적 분할을 반복하다 보면 과적합화는 피할 수 없이 나타나게 됨
31.2.2.2 과적합화를 피하기 위해 불필요한 가지(정보 제공이 그리 많지 않은 가지)를 제거함으로써 나무를 단순화하는 작업이 이루어지게 됨
- 첫번째 분할: Lot Size = 19,000
- 두번째 분할: Income = $84,000
- 모든 분할이 다 끝난 상태
31.4 단점 : 과적합화 문제
31.4.1 인공신경망에서의 학습과 동일한 문제 발생
classification-and-regression-trees
31.4.2 과적합화의 해소 방법
31.4.2.1 CHAID (chi-squared automatic interaction detection)
카이제곱 검정을 적용해, 적당한 수준에서 나무의 성장을 중단시키는 기법
31.4.2.2 CART
일단 나무를 최대한 성장시킨 다음, 가지치기를 수행
학습용 데이터로 나무를 성장시키고, 평가용 데이터(검정용 데이터)로 가지치기를 수행
31.4.2.3 C5.0
일단 나무를 최대한 성장시킨 다음, 가지치기를 수행
학습용 데이터가 나무의 성장과 가지치기에 모두 사용
31.5 실습예제(붓꽃 품종 분류)
붓꽃의 꽃잎(petal)과 꽃받침(sepal)의 폭과 길이를 측정하여 품종을 예측하는 예제
붓꽃의 품종은 150종류 이상이 있고 크게 3가지로 분류된(setosa, versicolor, virginica)
어떤 품종인지 구분해놓은 측정 데이터를 이용하여 새로 채집한 붓꽃의 품종을 예측하는 머신러닝 모델을 만드는 것이 목표
ln [1]:
# 사이킷런 패키지 로딩
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# 넘파이 패키지
import numpy as np
ln [2]:
# 붓꽃의 품종 종류
# 붓꽃 150 종류 이상의 품종이 있어서 품종을 분류하기가 매우 어려움
# 머신러닝을 이용하여 꽃잎과 꽃받침의 크기를 기반으로 분류
# 데이터 로딩
iris = datasets.load_iris()
# print(iris)
ln [3]:
# 데이터의 key 확인
print(iris.keys())
ln [4]:
# 데이터셋에 대한 설명, 앞부분
# print(iris['DESCR'][:193] + "\n...")
print(iris['DESCR'])
ln [5]:
# 우리가 예측하려는 붓꽃 품종의 이름
print("타깃의 이름: {}".format(iris['target_names']))
ln [6]:
print("특성의 이름: {}".format(iris['feature_names']))
ln [7]:
# 데이터의 크기 : 150행 4열
print("data의 크기: {}".format(iris['data'].shape))
ln [8]:
print("data의 처음 다섯 행:\n{}".format(iris['data'][:5]))
ln [9]:
import pandas as pd
# 데이터셋을 판다스의 데이터프레임으로 변환
df = pd.DataFrame(iris.data)
df.head()
ln [10]:
df.columns = iris.feature_names
df.head()
ln [11]:
df['result'] = iris.target
df
ln [12]:
# 2, 3열만 선택(3, 4번째 필드)
X = iris.data[:, [2, 3]]
y = iris.target
# 자동으로 데이터셋을 분리해주는 함수
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=0)
# 데이터 표준화 작업(0.0 ~ 1.0 사이의 값으로 표준화)
sc = StandardScaler()
sc.fit(X_train)
# 표준화된 데이터셋
X_train_std = sc.transform(X_train)
X_test_std = sc.transform(X_test)
print(X_train[:5])
print(X_train_std[:5])
ln [14]:
from sklearn.tree import export_graphviz
import pydotplus
import graphviz
from IPython.display import Image
# 의사결정나무의 단점 : 과거의 데이터는 잘 맞추지만 새로운 데이터에 대한 예측력이 약함
# 과적합화를 방지할 수 있는 대표적인 방법 중 하나가 랜덤포레스트
# 여러개의 의사결정나무를 만들고 투표를 통해 다수결로 결과를 결정함
# 처리가 빠르고 분류 정밀도가 높다.
# 랜덤 포레스트
from sklearn.ensemble import RandomForestClassifier
# 학습용 : 검증용 = 75 : 25
X_train, X_test, y_train, y_test = train_test_split(
cancer.data, cancer.target, random_state=0)
# 100개의 트리로 이루어진 랜덤 포레스트
# 기본 설정만으로도 좋은 결과를 얻을수도 있다.
forest = RandomForestClassifier(n_estimators=100, random_state=0)
forest.fit(X_train, y_train)
print("학습용 데이터셋 정확도: {:.3f}".format(forest.score(X_train, y_train)))
print("검증용 데이터셋 정확도: {:.3f}".format(forest.score(X_test, y_test)))
ln [54]:
# 최대 질문을 3으로 해서 가지치기 (max_depth 속성)
tree = DecisionTreeClassifier(max_depth=4, random_state=0)
# tree = DecisionTreeClassifier(random_state=0)
tree.fit(X_train, y_train)
print("학습용 데이터셋 정확도: {:.3f}".format(forest.score(X_train, y_train)))
print("검증용 데이터셋 정확도: {:.3f}".format(forest.score(X_test, y_test)))
ln [57]:
# 트리를 만드는 결정에 각 특성이 얼마나 중요한지를 평가하는 특성 중요도 적용
# 0~1 사이의 값
# 0 전혀 사용되지 않음
# 1 완벽하게 타겟 클래스 예측
def plot_feature_cancer(model):
n_features = cancer.data.shape[1]
plt.barh(range(n_features), model.feature_importances_,
align='center')
plt.yticks(np.arange(n_features), cancer.feature_names)
plt.xlabel("특성 중요도")
plt.ylabel("특성")
plt.ylim(-1, n_features)
plot_feature_cancer(tree)
ln [59]:
# 랜덤 포레스트에서 제공하는 각 트리의 특성 중요도
plot_feature_cancer(forest)
# worst radius보다 worst perimeter 특성이 더 중요한 것으로 나타남
# (가장 많은 정보를 가진 특성)
# 랜덤 포레스트는 더 넓은 시각으로 데이터를 바라볼 수 있다
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn import metrics
from sklearn.model_selection import train_test_split
# 데이터 로딩
mr = pd.read_csv("d:/data/mushroom/mushroom.csv", header=None)
# 데이터 내부의 기호를 숫자로 변환
label = []
data = []
attr_list = []
for row_index, row in mr.iterrows():
label.append(row.loc[0])
row_data = []
for v in row.loc[1:]:
# 문자를 숫자코드로 변환
row_data.append(ord(v))
data.append(row_data)
# 학습용 데이터셋과 검증용 데이터셋으로 나누기
data_train
ln [71]:
ch = 'A'
print(ch, ord(ch))
ch = 'a'
print(ch, ord(ch))