머신러닝 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(특성 선택) 해보기
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% 정확도를 쉽게 얻어낼 수 있음
'Machine Learning' 카테고리의 다른 글
머신러닝 선형 회귀 (0) | 2023.03.24 |
---|---|
머신러닝 앙상블(Ensemble) (0) | 2023.03.20 |
머신러닝 분류 평가 지표 (0) | 2023.03.12 |
머신러닝 기초 3, KNN모델을 이용한 붓꽃 품종 분류 실습 (0) | 2023.03.12 |
머신러닝 기초 2, 비만도 데이터 이용 학습 (0) | 2023.03.11 |
댓글