혼자 공부하는 머신러닝 + 딥러닝의 Chapter 5를 공부하면서 정리한 내용을 기반으로 작성하였다.
05-1. 결정트리
0. 결정트리 특징
- 이전 챕터에서 배운 로지스틱 함수는 이해하고 설명하기 어렵다. process의 flow chart를 그리는 듯이 쉽게 설명해 주는 모델이 있을까? 바로 결정트리 (Decision Tree) 모델이다.
- 다음과 같이 분류문제를 적용할 수도 있고, DecisionTreeRegressor를 이용해 회귀문제를 이용할 수 있다.
- 특성의 scale이 결정트리에 영향을 미치지 않기 때문에, 표준화 전처리(input_data - mean /std)를 할 필요 없다!
- 결정트리는 앙상블 학습 알고리즘(신경망과 함께 높은 성능을 냄)의 기반이 된다
from sklearn.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier()
dt.fit(train_data, train_target)
dt.score(test_data, test_target)
- DecisionTreeClassifier()의 매개변수 "가지치기(과대적합방지)"
- max_depth : 최대 깊이지정 → max_depth가 너무 크면 일반화가 잘 되지 않아 과대적합이 될 수 있다.
- min_impurity_decrease : 이 매개변수보다 특성 중요도 값이 더 작으면 더이상 분할하지 않는다.
1. 결정트리를 그려보자.
plot_tree에 결정트리 모델을 인자로 주는데, 여기에 추가하여 max_depth, filled, feature_names를 매개변수로 줄 수 있다.
- filled : 색 여부 (예를 들어, filled = True 하면, 클래스에 따라 색을 준다.)
- feature_names : 특성의 이름을 배열로 지정
import matplotlib.pyplot as plt
fromsklearn.tree import plot_tree
plt.figure(figsize=(10,7))
plot_tree(dt)
plt.show()
2. 결정 트리에서의 예측 결과
- 분류 문제 : 리프 노드에서 가장 많은 클래스가 곧 예측 클래스가 되는 것이다.
- 회귀 문제 : 리프 노드에 도달한 샘플의 타깃의 평균이 예측값이 된다.
- 특성 중요도는 feature_importances_속성에 저장된다.
3. DecisionTreeClassifier 클래스에서의 criterion : 기준이 무엇일까?
- 지니불순도 (Gini impurity; gini)
- 결정트리 분류모델의 criterion 매개변수 기본 값
- 지니 불순도 = 1 - (음성클래스 비율^2 + 양성클래스 비율^2)
- 엔트로피 불순도 (criterion = 'entropy')
- 정보 이득(information gain) : 부모와 자식 노드사이의 불순도 차이
- 부모 노드의 불순도 - (자식 노드의 불순도를 샘플 개수에 비례해 모두 더한 값)
- 결정 트리는 위와 같은 불순도 기준을 사용해서 정보 이득이 최대가 되도록 노드를 분할한다.
※ 특성 중요도 : 그 특성이 불순도를 감소하는데 얼마나 기여했는가
(1 ) 노드의 정보 이득 * 전체 샘플에 대한 비율를 각 특성별로 더한 값.
(2) 결정 트리 모델의 feature_importances_속성에 저장되어 df.feature_importances_ 이런 식으로 부를 수 있다.
(3) 특성 중요도 값이 min_inmpurity_decrease에 지정한 값보다 작으면 더 이상 분할하지 않게 설정할 수 있다.
05-2. 교차 검증과 그리드 서치
교차 검증
1. 검증세트
- 테스트 세트를 사용해서 모델이 과대적합/과소적합인지, 성능은 어떤지 사용해왔는데, 계속해서 테스트 세트를 적용시키다 보면 모델의 성능은 테스트 세트에 맞춰지게 된다. 이제, 검증 세트(validation set)를 이용해 보자.
- 총 데이터 (100%) = 훈련세트 (60%) + 검증세트(20%) + 테스트세트(20%) 이런 식으로 훈련세트를 더 쪼개는 것이다.
- train_test_split 2번 해서 검증세트를 만들 수도 있다 : 훈련세트 + 테스트세트(20%) → 훈련세트 + 검증세트(20%)
from sklearn.model_selection import train_test_Split
tmp_train_input, test_input, tmp_train_target, test_target
= train_test_split(data, target, test_Size=0.2)
train_input, val_input, train_target, val_target
= train_test_split(tmp_train_input, tmp_train_target, test_Size=0.2)
2. 교차 검증
- 검증 세트 크기가 너무 작다면 검증 점수가 일정하지 않고 불안정할 것이다. 이때, 교차검증을 통해 해결할 수 있다.
- 교차 검증은 훈련세트에서 검증세트를 떼어내고 평가하는 과정을 반복하는 것이다.
- k-폴드 교차 검증(k-겹교차 검증)
- 훈련세트를 5 부분으로 나눠 교차 검증 수행하면 5-폴드 교차 검증이 된다.
- 물론 많이 쪼갤수록 검승 세트 크기 또한 줄어든다. 다만, 각 부분에서의 검증 점수를 평균하기 때문에 안정된 점수를 받을 수 있다.
- 5-폴드 교차 검증일 때, 훈련세트(전체 데이터의 80%) =
- 훈련세트 + 훈련세트 + 훈련세트 + 훈련세트 + 검증세트,
- 훈련세트 + 훈련세트 + 훈련세트 + 검증세트 + 훈련세트,
- 훈련세트 + 훈련세트 + 검증세트 + 훈련세트 + 훈련세트,
- 훈련세트 + 검증세트 + 훈련세트 + 훈련세트 + 훈련세트,
- 검증세트 + 훈련세트 + 훈련세트 + 훈련세트 + 훈련세트
- 교차 검증 : cross_validate()
- 5-폴드 교차 검증을 수행하며, 훈련시간과 검증시간, 검증 폴드 점수(fit_time, score_time, train_target)를 반환한다.
- → train_target의 배열값을 평균해서 평균 교차 검증 점수를 구할 수 있다.
- 분할기(splitter) 지정 : StratifiedKFold() 혹은 KFold()
- train_test_split()으로 훈련세트와 테스트세트를 나눴다면, splitter을 지정할 필요 없다. 다만, 교차검증을 할 때, 훈련세트를 섞고 싶다면, 분할기를 지정해야 한다.
- 분류 모델은 StratifiedFold, 회귀 모델은 KFold를 보통 지정한다.
from sklearn.model_selection import cross_validate
from sklearn.model_selection import StratifiedKFold
scores = cross_validate(dt, train_input, train_target, cv=StratifiedKFold())
그리드서치와 랜덤서치
1. 그리드 서치
- 하이퍼 파라미터 탐색과 교차 검증 한 번에 수행 → 각 하이퍼 파라미터의 최적값을 찾는 것을 자동화해 준다.
- n_jobs : 병렬 실행하는 데 사용할 CPU 코어수 (-1은 전부)
import numpy as np
params = {
'min_impurity_decrease' : np.arange(0.0001, 0.001, 0.0001),
'max_depth' : range(1, 10, 1),
'min_samples_split' : range(1, 100, 10)
}
from sklearn.model_selection import GridSearchCV
gs = GridSearchCV(DecisionTreeClassifier(), params, n_jobs = -1)
gs.fit(train_input, train_target)
gs.best_params_ #파라미터 최적값
np.max(gs.cv_results_['mean_test_score']) #검증 점수 최댓값
2. 랜덤 서치
- 확률분포를 이용하기 때문에, 연속적인 매개변수의 최적값을 찾을 때 유용하다.
- 그리드 서치에서의 params를 보면, 각 파라미터의 값들을 나열해서 전달하였다. 하지만, 랜덤 서치에서는 확률 분포를 대신 전달해서 샘플링할 수 있게 한다.
- n_iter : 샘플링 횟수 지정하여 시스템 자원을 상황에 맞게 쓸 수 있다.
from scipy.stats import uniform, randint
params = {
'min_impurity_decrease' : uniform(0.0001, 0.001),
'max_depth' : randint(10, 20),
'min_samples_split' : randint(2, 20),
'min_samples_leaf' : randint(1, 20)
}
from sklearn.model_selection import RandomizedSearchCV
rs = RandomizedSearchCV(DecisionTreeClassifier(), params, n_iter=100, n_jobs=-1)
rs.fit(train_input, train_target)
rs.best_params_
np.max(rs.cv_results_['mean_test_score'])
05-3. 트리의 앙상블
앙상블 학습(ensemble learning)
- 비정형 데이터에는 신경망 알고리즘을 사용한다.
하지만, csv와 같은 정형데이터를 다루는 데에는 앙상블 학습 알고리즘을 사용해 높은 성과를 낼 수 있다.
Random Forest(랜덤 포레스트)
- 안정적인 성능을 내는 앙상블 학습 대표 알고리즘
- 앞서 배운 DecisionTree를 랜덤하게 여러 개 만들어 숲을 만든다.
- 기본 100개의 결정트리를 아래의 방식으로 훈련한다.
- 훈련 데이터를 부트스트랩 방식으로 샘플링하고 분류해서 각 트리를 위한 훈련 데이터를 만든다.
- 분류의 경우, 특성 집합에서 특성을 제곱근만큼 랜덤하게 선택한다. (ex. 9의 특성이 있다면 3개를 선택하는 식)
- 단, 회귀의 경우 전체 특성을 사용한다.
- 최선의 분할을 선택한다.
- 분류일 때는, 각 트리마다 클래스별 확률을 평균해서 가장 높은 확률의 클래스를 예측으로 한다.
- 회귀일 때는, 각 트리의 예측값을 평균한다.
- 기본 100개의 결정트리를 아래의 방식으로 훈련한다.
- 훈련 데이터와 특성을 모두 랜덤하게 선택하기 때문에, overfitting을 막을 수 있고 검증 세트와 테스트 세트에서 안정적인 성능을 얻을 수 있다.
from sklearn.model_selection import cross_validate
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier(n_jobs =-1) #RandomForestClassifier : 회귀
rf.fit(train_input, train_target)
print(rf.feature_importances_)
- rf.feature_importances_를 확인해보면
- 일부 특성의 특성 중요도가 결정트리에서보다 상승한 것을 볼 수 있다.
- 이는 랜덤 포레스트가 결정 트리보다 하나의 특성에 과도하게 집중하지 않고 많은 특성이 훈련에 기여할 수 있게 한다는 것을 알 수 있다.
물론, 교차 검증을 통해 검증 점수와 테스트 점수를 확인할 수도 있다.
Extra Tree(엑스트라 트리)
- Random Forest와 매우 비슷하게 동작하지만, 차이점 2개가 있다.
- 부트스트랩 샘플을 사용하지 않고, 전체 훈련세트를 사용한다.
- 노드를 분할할 대, 최선의 분할을 선택하는 것이 아니라, 무직위로 분할한다.
- 랜덤 포레스트보다 무작위성이 좀 더 크기 때문에, 계산 속도가 빠르지만 더 많은 결정트리를 훈련해야 한다.
from sklearn.ensemble import ExtraTreesClassifier
et = ExtraTreesClassifier(n_jobs=-1) #ExtraTreesRegressor : 회귀
et.fit(train_input, train_target)
print(et.feature_importances_)
물론, 교차 검증을 통해 검증 점수와 테스트 점수를 확인할 수도 있다.
Gradient Boosting(그레이디언트 부스팅)
- 경사 하강법을 사용하여 트리를 앙상블에 추가한다.
- 깊이가 얕은 결정 트리를 사용한다.
- 깊이가 얕기 때문에, 결정 트리의 개수를 늘려도 과대적합이 잘 일어나지 않는다.
- 학습률(learning_rate) 매개변수를 이용해 학습률을 증가시키고 트리 수를 늘리면, 성능을 향상시킬 수 있다.
- 분류 : 로지스틱 손실 함수를 사용
- 회귀 : 평균 제곱 오차 함수를 사용
from sklearn.ensemble import GradientBoostingClassifier
gb = GradientBoostingClassifier(n_estimators = 500, learning_rate=0.2)
scores = cross_validate(gb, train_input, train_target, return_train_Score = True, n_jobs = -1)
print(np.mean(scores['train_score']), np.mean(scores['test_score']))
gb.fit(train_input, train_target)
print(gb.feature_importances_)
- 물론, feature_importances_를 통해, 특성 중요도를 제공한다.
- 랜덤 포레스트보다 일부 특성에 더 집중할 수 있다.
**참고
pandas 데이터프레임 상세정보보기 1. dataFrame.head() 2. dataFrame.info() : 각 열의 데이터 타입과 null값인지 아닌지를 알 수 있다. 3. dataFrame.desrcibe() : mean, std, min, max, median, 상위/하위 25%의 수를 볼 수 있다. |
- 모델 파라미터 : 머신러닝 모델이 학습하는 파라미터 - 하이퍼 파라미터 : 우리가 직접 지정하는 것 (ex. max_depth) |
부트스트랩 방식 - 샘플 1000개 중 100개의 샘플을 뽑는다면, 샘플을 꺼내고 다시 넣고를 반복해 하나의 샘플을 중복해서 뽑을 수 있게 한다. - 예를 들어 주머니 내 흰돌 1개 검은돌 1개가 있고 부트스트랩 방식으로 3개를 뽑으면, 흰/흰/흰이라는 샘플이 나올 수 있다. |
'머신러닝 > 혼공머신' 카테고리의 다른 글
[혼공머신] chapter 6. 군집 알고리즘 (0) | 2023.01.31 |
---|---|
[혼공머신] chapter 3. 회귀 - k최근접, 릿지/라쏘 (0) | 2022.12.01 |
[혼공머신] chapter 2. k-최근접 이웃 알고리즘 - 실습 (0) | 2022.11.24 |
[혼공머신] chapter 2. k-최근접 이웃 알고리즘 - 데이터전처리 (0) | 2022.11.24 |
[혼공머신] chapter 1. 머신러닝이란? (0) | 2022.11.17 |