결정트리와 교차검증, 그리드 서치, 그리고 앙상블에 대해 배운다
결정 트리
결정트리는 분류 문제를 해결하는 알고리즘 중 하나이다.
로지스틱 회귀가 잘 안될 때 결정트리로 로지스틱 회귀의 목적(어떤 데이터가 무엇에 해당하는지 아닌지)을 더 정확하게 달성하는 경우가 있다. 왜 그럴까? <준비중>
결정 트리의 구현
from sklearn.tree import DecisionTreeClassifier
<dt_name> = DecisionTreeClassifier([random_state = <n>])
dt.fit(<train_feature_scaled>, <train_target>)
(주의!) target은 스케일러가 적용되지 않는 이유는, 회귀의 종속변수가 아니라 클래스(카테고리)를 나타내기 때문이다!
(정보) 결정트리는 스케일러를 사용하는 전처리 과정이 필요없다.
결정 트리 보기
import matplotlib.pyplot as plt
from sklearn.tree import plot_tree
plt.figure([figsize=(<inch>, <inch>)]) #창 크기 설정
plot_tree(<dt_name>)
plt.show()
Tip) 결정 트리 더 편하게 보기
plot_tree(<dt_name>[, max_depth = <n>][, filled = T/F][, feature_names = <list>])
max_depth는 트리의 깊이(= 레벨-1)를 뜻한다.
filled 옵션은 클래스 해당 유무마다 구별되도록 노드에 색을 칠한다.
-> 노드마다 더 많은 데이터 수를 가진 클래스가 해당 클래스 인걸로 판단함.
feature_names옵션은 노드에 지정한 이름을 사용하여 표기한다.
결정 트리 노드의 해석
각 노드는 다음과 같은 정보가 담겨있다.
1. 테스트 조건
2. 불순도
3. 총 샘플 수(트리를 타고 갈 때 해당 노드에 남아있는 데이터 수)
4. 클래스별 샘플 수(총 샘플 수 중에서 음성/양성 클래스의 갯수)
예시)
salt <= -0.538
gini = 0.348
samples = 711
value = [34, 677]
불순도(gini)
gini는 지니 불순도를 의미한다. gini를 통해 테스트 조건을 생성한다.
지니 불순도는 다음과 같이 구한다.
지니 불순도 = 1 - (음성클래스 비율)^2 - (양성클래스 비율)^2
지니 불순도의 최솟값은 0이다. 이것은 어느 한 클래스의 데이터만으로 이루어져 있다는 것으로, 가장 순수하다.
지니 불순도의 최댓값은 0.5이다. 이것은 모든 클래스의 데이터가 똑같은 갯수로 있다는 것으로, 가장 순수하지 못하다.
결정트리의 노드는 자신의 자식 노드와의 불순도 차이가 가능한 '크도록' 조건을 만든다.
지니 불순도 차이는 다음과 같이 구한다. (지니 불순도 차이를 정보 이득(information gain)이라고도 한다.)
부모의 불순도 -
(왼쪽 노드 샘플수 / 부모의 샘플 수) X 왼쪽 노드 불순도 -
(오른쪽 노드 샘플 수 / 부모의 샘플 수) X 오른쪽 노드 불순도 = 지니 불순도 차이
Why?) 왜 정보이득의 공식은 저럴까?
일단 볼드체 처리한 항이 조건식을 만들 때 변수로 작용하는 부분이다. 즉 왼쪽/오른쪽 자식노드의 샘플수 x 불순도를 최대한 작게 만들어야 한다.
즉 자식노드의 불순도를 최대한 작게 함으로써 자식 노드가 더 확실하게 판별을 할 수 있게하기 위함이다. 그리고 샘플수가 적을수록 같은 불순도여도 더 확실하게 판별할 수 있어서, 샘플수도 노드의 정확도에 영향을 주기 때문에 곱하기 관계로 놓은 것이다.
Tip) 최적화 알고리즘은, 여러 요소들 중에서 최대, 또는 최소와 같은 극단적인 값을 찾으려는 요소가 반드시 1개 이상이어야 한다.
엔트로피 불순도
<준비중>
가지 치기
트리의 레벨이 너무 높으면 overfitting 현상이 일어나 train데이터 세트에만 잘 맞고 새로운 데이터에는 잘 안맞는 문제가 발생한다. 따라서 가지치기 과정을 통해 레벨을 조정할 필요가 있다.
<dt_name> = DecisionTreeClassifier([max_depth = <n>][, random_state = <n>])
max_depth 옵션을 통해 트리의 최대 깊이를 제한할 수 있다.
마지막으로 결정트리는 어떤 특성(column)이 가장 유용한지 보여주는 함수를 가지고 있다.
dt.feature_importances_
리스트 형태로 나오는데, 각 리스트의 원소는 해당 특성(column)의 중요도 비율이다.
머신러닝 모델은 종종 블랙박스와 같다고 불린다. 왜냐하면 coefficient와 intercept는 왜 그런 값으로 학습되었는지 설명하기가 어렵기 때문이다.
결정 트리는 많은 앙상블 학습 알고리즘의 기반이 된다. 앙상블 학습 알고리즘은 신경망과 함께 가장 높은 성능을 내기 때문에 인기가 높다.
교차 검증
검증세트
검증세트란 훈련 데이터셋을 또 나누는 개념으로, 테스트 세트를 한 번만 사용하기 위해 만든 세트이다.
모델 훈련은 훈련데이터셋으로 한다.
모델 평가는 검증데이터셋으로 한다.
마지막으로 완성 전 테스트데이터셋으로 평가한다.
보통 훈련/검증/테스트 데이터 비율은 6:2:2 정도이다.
교차 검증이란
교차 검증(Cross Validation)이란 검증세트로 모델을 평가하는 것을 여러번 반복하는 것이다. 그리고 이 점수들의 평균이 교차 검증의 점수가 된다.
Why?) train+test세트가 아니라 train+validation+test 세트로 나누는가?
그 이유는 평가를 위한 데이터 세트가 한 종류만 있으면 그 한 세트를 위해서만 모든 튜닝이 이루어지기 때문에 overfitting이 발생한다. 즉 학습+평가를 하는 한 싸이클에서 하이퍼파라미터 튜닝 등을 하는데, 평가 데이터 종류가 하나만 있다면 모든 튜닝이 그 세트에만 맞춰지기 때문이다.
그래서 교차 검증에서는 기존 train세트에서 일정 부분을 validation세트로 하고, 하이퍼파라미터 튜닝을 한 뒤에 (훈련용 데이터 세트 내부에서)validation세트의 내용을 바꿔가면서 훈련+평가를 실시한다. (k-fold validation)
K-fold Cross Validation
동일한 검증 데이터 세트에 과적합되지 않도록 검증 데이터셋을 매 검증마다 바꿔서 하는데 이것을 k-fold 교차검증 이라고 한다.
위의 그림은 3-fold 교차검증이다. 보통은 5-fold나 10-fold를 사용한다.
K-fold 교차검증 구현
from sklearn.model_selection import cross_validate
<dictionary> = cross_validate(<model_obj>, <train+validate_feature>, <train+validate_target>)
참고로 cross_validate함수의 기본값은 5-fold이다. cv옵션으로 k값을 바꿀 수 있다.
이렇게 cross_validate함수를 호출하면 해당 model_obj 객체가 학습+검증이 된다.
Tip) cross_validate함수 자체는 훈련세트를 섞는(shuffle) 과정이 없다. 따라서 섞는 기능을 추가하려면 StratifiedKFold함수를 사용한다.
from sklearn.model_selection import StratifiedKFold
splitter = StratifiedKFold([n_splits = <n>][, shuffle = T/F][, random_state = <n>])
<dictionary> = cross_validate(<model_obj>, <train+validate_feature>, <train+validate_target>[, cv = splitter])
n_splits: k값을 말한다.
shuffle: 데이터를 섞을지 말지를 결정한다.
random_state: 랜덤 시드값
하이퍼 파라미터 튜닝
k-fold 교차검증을 한다면, train+validation 한 싸이클을 돌 때마다 하이퍼 파라미터를 조금씩 튜닝하게 된다.
(하이퍼 파라미터란, 모델이 학습하는 파라미터가 아닌 학습자가 직접 설정해 줘야하는 파라미터를 말한다. 즉 모델 자체의 설정값)
(주의!) 하이퍼파라미터들은 반드시 "동시에" 튜닝함으로써 최적의 값을 찾아야 한다. 하나에 대해서만 최적의 값을 찾고 그 다음 하이퍼파라미터의 최적의 값을 찾으려고 하면 안된다.
어떤 모델에 대한 최적의 하이퍼파라미터를 찾는 과정은 수작업으로는 결코 쉬운일이 아니다. 따라서 이것을 자동화한 python패키지가 있는데 Grid Search패키지 라고 한다.
GridSearchCV클래스
사이킷런의 GridSearchCV클래스는 하이퍼파라미터 최적화+교차검증을 한 번에 수행해 준다. 즉 별도로 cross_validate함수를 호출할 필요가 없다.
사용법은 원래 모델객체 생성->학습 사용법에서 GridSearchCV객체가 끼어든다는 차이가 있다.
from sklearn.model_selection import GridSearchCV
params = <dictionary>
gs = GridSearchCV(<model_obj>, params[, n_jobs = <n>])
gs.fit(<train+validation_input>, <train+validation_target>)
n_jobs: CPU 코어 사용 갯수로, -1일 경우 모든 코어를 사용한다.
params변수: dictionary자료형으로, key값엔 하이퍼파라미터 이름이, value값에는 학습을 시도할 때 쓰일 하이퍼파라미터 값들의 list가 들어간다. 즉 list의 한 요소별로 하이퍼파라미터에 대입해서 각각 학습을 시도하는 것이다.
k-fold의 k값은 기본값은 5이다. 따라서 value의 list자료형의 길이가 8이고 k가 5라면 총 8x5=40개의 모델을 훈련한다.
<model_obj> = gs.best_estimator_ 을 하게되면, model_obj에 최적의 파라미터를 가진 모델객체가 대입된다.
최적의 하이퍼파라미터의 값은 gs.best_params_에 있다.
랜덤 서치
<준비중>
앙상블
정형/비정형 데이터
정형 데이터란 데이터의 원래 형태가 특정 구조로 되어 있는 데이터다. 쉽게 말하자면 수치로 정확하게 표현할 수 있는 데이터를 말한다.
e.g.) 물건의 갯수: 물건의 갯수는 원래부터 숫자로 표현 가능하기 때문에 정형 데이터이다.
물건의 길이: 물건의 길이도 원래 데이터가 "측정된 수치"이기 때문에 정형 데이터다.
비정형 데이터란 원래의 데이터가 특정 구조로 설명하기 어려운 데이터다. 쉽게 말하자면 원래의 데이터를 수치로 치환하거나 근사시켜 표현할 수 있는 데이터를 말한다.
e.g.) sentence: 문자(character) 하나는 정형 데이터이지만, 그 정형 데이터인 문자의 배치가 어떤 절대적인 공식으로 나오지 않기 때문에 원래 데이터는 수학적 공식이나 수치가 없다.
사진: 사람이 눈으로 보는 것들은 수치로 이뤄지지 않고, 빛이나 원소같은 자연적인 것들로 이루어져 있다. 사진은 풍경을 이미지센서가 감지한 뒤 ADC과정을 거쳐 디지털화해 수치로 근사시킨 데이터다.
앙상블이란?
앙상블은 정형 데이터를 다루는 데 가장 뛰어난 성과를 내는 알고리즘이다.
이 알고리즘은 대부분 결정트리를 기반으로 만들어진다.
(정보) 비정형 데이터를 다루는데 가장 뛰어난 성과를 내는 알고리즘은 신경망 알고리즘이다.
랜덤 포레스트
랜덤 포레스트는 앙상블 학습의 대표 중 하나로, 안정적인 성능 덕에 많이 사용된다.
랜덤 포레스트는 말 그대로 결정트리가 여러개 모여 포레스트를 이루고, 각 결정트리가 랜덤하게 훈련데이터를 사용하게 된다.
부트스트랩 샘플
포레스트 내부의 각 결정트리는 전체 train 데이터 셋에서 각자 train에 사용할 데이터들을 뽑아간다. 이 때 핵심은 뽑아간 데이터 중에서 서로 중복된 데이터가 있을 수 있다.
쉽게 말하자면 1000개의 train 데이터가 있을 때, 500개의 데이터를 뽑아간다고 하면 1000개 데이터 중에서 데이터 1개를 뽑고 그걸 다시 넣은 후 똑같이 1000개 중에서 데이터 1개를 뽑고 그것을 총 500회 반복한다.
이렇게 결정트리들이 각자 뽑은 train데이터 셋을 부트스트랩 샘플 이라고 한다.
Tip) 보통 전체 train 데이터 갯수와 부트스트랩 샘플 데이터 갯수를 동일하게 한다.
또한
랜덤 특성 선택
랜덤 포레스트는 (정확히는 랜덤포레스트Classifier) 각 노드를 분할할 때 부모노드의 특성(column)갯수의 square root갯수만큼 자식노드가 가져가고 그 특성들 중에서 가장 적합한 특성을 선택한다.
(복습) 지도학습에는 회귀와 분류가 있다.
회귀는 연속적인 값을 예측하고, 분류는 이산적인 값(class)을 예측한다.
랜덤 특성이 들어가 있기 때문에 overfitting을 막아주는 효과가 있다.
랜덤 포레스트 사용
from sklearn.ensemble import RandomForestClassifier
<rf_obj> = RandomForestClassifier([n_jobs = <n>][, random_state = <n>])
이렇게 랜덤포레스트 객체를 만든 뒤 cross_validate같은 함수로 학습 시키고 평가하면 된다.
(정보) 랜덤 포레스트는 결정트리의 모임이기 때문에 결정트리의 옵션을 모두 사용할 수 있다.
예를들면 criterion, max_depth 등등
Out of Bag(OOB)
랜덤포레스트에서 부트스트랩 샘플을 추출할 때, 단 한번도 추출되지 않고 남겨진 데이터들이 존재할 수 있다. 그런 데이터들을 Out of Bag샘플이라고 한다. 이러한 남겨진 데이터들을 버리지 않고 유용하게 사용할 수 있는 방법이 있는데, 바로 validation 데이터셋으로 활용하는 것이다.
OOB를 validation데이터셋으로 사용하려면 랜덤포레스트 객체의 옵션을 oob_score = True로 설정해야 한다.
엑스트라 트리
<준비중>
그레이디언트 부스팅
<준비중>
그레이디언트 부스팅은 경사하강법과 방법이 유사하다.
히스토그램 기반 그레이디언트 부스팅
<준비중>
[PLAYDATA] 데이터 엔지니어링 9월 3주차 9/14 (0) | 2023.09.14 |
---|---|
[PLAYDATA] 데이터 엔지니어링 9월 3주차 9/13 (0) | 2023.09.13 |
[PLAYDATA] 데이터 엔지니어링 9월 2주차 9/8 (0) | 2023.09.08 |
[PLAYDATA] 데이터 엔지니어링 9월 2주차 9/7 (0) | 2023.09.07 |
[PLAYDATA] 데이터 엔지니어링 9월 2주차 9/6 (0) | 2023.09.06 |