본문 바로가기
Machine Learning

머신러닝 Decision Tree, 교차 검증, 특성 선택

by wanttosleep1111 2023. 3. 20.

머신러닝 Decision Tree, 교차 검증

 

1. Decision Tree : 결정 트리 모델

  • 스무고개를 하듯 예/아니오 질문을 반복하며 학습
  • 특정 기준(질문)에 따라 데이터를 구분하는 모델
  • 분류와 회귀에 모두 사용 가능


  • 지니 불순도 (Gini Impurity)
    해당 범주 안에 서로 다른 데이터가 얼마나 섞여 있는지를 뜻함
    결정 트리 모델의 노드 분할 기준
    각 질문들이 얼마나 좋은 질문인지 수치로 파악 가능
    0 ~ 0.5 사이 값을 범위로 가짐
    불순도가 0에 가까울수록 잘 분류된 것 (좋은 질문)
    불순도가 0.5라면 데이터가 5:5 비율로 섞여서 분류된 것 (좋지 않은 질문)

 

※ 지니 불순도 예시

A와 B 방법으로 데이터 분류 비교

 

  • 엔트로피 (Entropy)
    해당 범주 안에 같은 데이터가 얼마나 포함되어 있는지를 뜻함
    결정 트리 모델의 노드 분할 기준
    각 질문들이 얼마나 좋은 질문인지 수치로 파악 가능
    0 ~ 1 사이 값을 범위로 가짐
    데이터의 순도가 높아질수록 엔트로피는 작아진다 → 엔트로피가 작을수록 좋지 않은 질문
    데이터의 순도가 낮아질수록 엔트로피는 커진다 → 엔트로피가 클수록 좋은 질문

※ 불순도 측정 비교

그래프의 최댓값이 다르고, 엔트로피의 경사도가 좀 더 심하기 때문에 데이터에 더 민감하게 반응

 

  • Decision Tree 의사 결정 방향 → 불순도가 낮아지는 방향
    ※ 하이퍼 파라미터를 설정하지 않을 경우 모두 나눠질 때까지 뻗어나가게 됨

 

  • 용어

 

 

2. 교차 검증

  • 모델의 일반화 성능 측정 방법 → 모든 데이터에 대해 모델이 얼마나 잘 맞추는지 평가
    (한번 나누고 한번 훈련하는 평가 방법보다 더 안정화된 통계적 평가 가능)
  • 방법론 : 훈련 세트와 테스트 세트로, 여러 부분으로 나눈 후에 평가
  • 모델을 정의하고 학습하기 전에 정확도가 어느 정도일지 확인 가능
  • cross_val_score(모델, X_train, y_train, cv=)

 

3. 특성 선택 (feature selection)

  • 지도학습 모델에서는 데이터의 각 특성 중요도를 출력할 수 있음
    특성 중요도 : 정답에 영향을 미치는 정도
  • 각 특성들은 0~1 사이의 중요도 값을 가지며, 모든 특성 중요도의 합은 1
  • 0이 나오는 컬럼은 모델이 정답을 예측하는데 전혀 도움이 되지 않으며, 정답 예측에 도움이 많이 되는 특성일수록 1에 가깝게 나옴
  • 1이 나오는 컬럼 : 정답을 정확하게 예측하는 컬럼
    (1인 특성이 있다면 모델이 정답을 예측하는데 다른 특성은 아예 필요가 없음)

 

▶ 예제

버섯데이터 분류

  • 버섯들의 특징을 확인하여 독과 식용 버섯을 분류
  • Decision Tree 시각화 & 과대적합 속성을 제어
  • Feature Selection(특성 선택) 해보기

mushroom.csv
0.36MB

 

 

 

1. 필요 라이브러리 불러오기

import pandas as pd
from sklearn.model_selection import train_test_split # 데이터를 랜덤으로 분할
from sklearn.tree import DecisionTreeClassifier # 의사결정나무 분류 모델

 

2. 데이터 불러오기

# 데이터 불러오기
data = pd.read_csv("./data/mushroom.csv")
data
# 데이터 프레임 옵션 설정 (전체 컬럼 확인)
pd.set_option('display.max_columns', None)

 

3. 전체 컬럼과 결측치 확인

.info()

data.info()

 

4. 문제 데이터 X와 정답 데이터 y로 분리 (정답 데이터 : poisonous)

# 문제 X와 정답 y로 데이터를 분리
# 정답 y데이터 : 'poisonous'
X = data.loc[:,'cap-shape':]
y = data.loc[:,'poisonous']

 

5. 기술통계 : 범주형 기술통계 확인

unique : 값의 종류

top : 가장 많은 값

freq : 가장 많은 값의 수

# 기술통계 -> 범주형 데이터 기술통계 확인
data.describe()

 

6. 정답(y데이터) 라벨별 개수 확인

.value_counts()

# 정답(y데이터) 라벨별 개수 확인
y.value_counts()

 


 

7. 인코딩을 해서 범주형 데이터를 수치형 데이터로 바꿔주기

  • Label 인코딩 : 각각 label 숫자로 바꿔주는 방법 (분류에서만 사용, 회귀에서는 사용 불가)
  • one-hot 인코딩 : 분류하고자 하는 범주만큼 자릿수를 만들고 단 한 개의 1과 나머지는 0으로 채워주는 방법
    (단 하나의 1과 나머지 0으로 나누고 컬럼별로 나눠버림)

① Label 인코딩

X['cap-color'].unique()

color_dict = {
    'n' : 1,
    'y' : 2,
    'w' : 3,
    'g' : 4,
    'e' : 5,
    'p' : 6,
    'b' : 7,
    'u' : 8,
    'c' : 9,
    'r' : 10
}
X['cap-color'].map(color_dict)

 

② one-hot 인코딩 : 값의 크고 작음이 의미가 없을 때 (대부분 one-hot 사용)

pd.get_dummies(데이터)

# one hot 인코딩 -> 값의 크고 작음이 의미가 없을 때
X_one_hot = pd.get_dummies(X)
X_one_hot

 

X_one_hot.info()

 


 

8. 모델링

① 데이터 분할

# 데이터 분할 
X_train, X_test, y_train, y_test = train_test_split(X_one_hot, y, 
                                                   test_size = 0.3,
                                                   random_state = 1)
print(X_train.shape)
print(y_train.shape)
print(X_test.shape)
print(y_test.shape)

② 모델 생성, 학습, 정확도 평가

# 모델 생성
tree = DecisionTreeClassifier()
# 모델 학습
tree.fit(X_train, y_train)
# 모델 정확도 평가
tree.score(X_test, y_test)

 


 

9. 교차검증

from sklearn.model_selection import cross_val_score
rs = cross_val_score(tree, X_train, y_train, cv = 5)
rs.mean()

 


 

10. tree 모델 시각화

import graphviz
from sklearn.tree import export_graphviz
export_graphviz(tree, out_file = 'tree.dot',
               class_names = ['독', '식용'],
               feature_names = X_one_hot.columns,
               impurity = True, # 지니 불순도 출력 여부
               filled = True) # 각 노드들의 클래스가 구분되게 색칠 여부
# 위에서 만든 파일로 시각화 확인을 진행
with open('./tree.dot', encoding='UTF-8') as f :
    dot_graph = f.read()

display(graphviz.Source(dot_graph))
# 그래프를 이미지파일로 저장
graph = graphviz.Source(dot_graph)
graph.render(filename='test_img', directory='./', format='png')

 

 


 

11. 하이퍼파라미터 조정

tree2 = DecisionTreeClassifier(max_depth = 5)
# 모델 학습
tree2.fit(X_train, y_train)
# 모델 평가
print(tree2.score(X_test, y_test))
print(cross_val_score(tree2, X_train, y_train, cv = 5))

 

# 파일화
export_graphviz(tree2, out_file = 'tree2.dot',
               class_names = ['독', '식용'],                
               feature_names = X_one_hot.columns,
               impurity = False, # 지니 불순도 출력 여부
               filled = True) # 각 노드들의 클래스가 구분되게 색칠 여부

# 그래프 불러오기
with open('./tree2.dot', encoding='UTF-8') as f :
    dot_graph2 = f.read()

display(graphviz.Source(dot_graph2))
graph2 = graphviz.Source(dot_graph2)
graph2.render(filename='test2_img', directory='./', format='png')

 

 

for 문을 이용해 하이퍼파라미터 max_depth를 1~11까지 조정

train_list = []
test_list = []

for k in range(1, 11) :
    tree_model = DecisionTreeClassifier(max_depth = k)
    tree_model.fit(X_train, y_train)
    
    train_score = tree_model.score(X_train, y_train)
    train_list.append(train_score)
    
    test_score = tree_model.score(X_test, y_test)
    test_list.append(test_score)

그래프 출력

import matplotlib.pyplot as plt
plt.figure(figsize = (15, 5))
plt.plot(range(1,11), train_list, label='train_acc')
plt.plot(range(1,11), test_list, label='test_acc')
plt.xticks(range(1, 11))
plt.legend()
plt.grid()
plt.show()

 


 

12. 특성 선택 (feature selection)

# 트리 모델에 대한 특성 중요도 확인
# fi(feature importances)
fi = tree.feature_importances_
fi

# 특성 중요도를 데이터 프레임으로 만들기
fi_df = pd.DataFrame(fi, index=X_one_hot.columns, columns=['특성중요도'])
# inplace(boolean) 속성 : True일 때, 데이터를 바로 변수에 저장
fi_df.sort_values(by='특성중요도', ascending = False, inplace = True)
fi_df

 

tree 모델 내부 시각화 표를 보면 가장 중요도가 높은 odor_n 컬럼을 우선적으로 고려한 것을 확인 가능

(중요도가 가장 높은 컬럼을 먼저 고려해야 효율적 분류 가능)

현재 버섯 데이터 세트는 odor_n 컬럼이 60% 이상의 중요도를 혼자 차지하기 때문에 모델 학습하기 용이하며, 100% 정확도를 쉽게 얻어낼 수 있음

댓글