본문 바로가기

deeplearning

혼공머신 4주차 (5. 트리 알고리즘)

오늘은 5. 트리 알고리즘에 대한 내용이다! 분류에 대체적으로 집중하고 있는 느낌이라서 분류하는데 쓰이는 모델들을 많이 알게 된 것 같아서 좋았다. 

기존에 다중 분류 문제는 로지스틱 회귀를 이용하여 해결하였다. 그래서 나는 로지스틱 회귀가 전부인줄 알았으나,, 당연히 아니었다.

 

https://colab.research.google.com/drive/1lr42lH7tyEAa0Ems3OliBazSL6ukyF36#scrollTo=aHStuoduT2T

코랩 파일이다,, 이번에는 한번 바꿔서 주석 달기보다 블로그에 정리했는데... 뭐가 나은건지 아직도 잘 모르겠다! 선택 미션은 손코딩이라 캡쳐 대신 파일로 대신한다.

 

05_트리_알고리즘.ipynb

Colaboratory notebook

colab.research.google.com

결정 트리 모델

결정 트리는 하나의 기준에 대해 예/아니오로 훈련셋을 2개씩으로 나누면서 결국 트리 형태를 띄도록 하면서 분류하는 것이다. 평소에 모델 훈련하던 것과 똑같이 fit을 쓰면 되고, 점수도 똑같이 출력할 수 있다.

 

from sklearn.tree import DecisionTreeClassifier
dt=DecisionTreeClassifier()
dt.fit(train_scaled, train_target)
dt.score(train_scaled, train_target)

 

트리를 그리려면 sklearn.tree에서 plot_tree를 임포트하면 된다. plot_tree의 매개변수에서 dt는 내가 그릴 트리, max_depth는 루트 노드를 제외한 깊이(?), fill는 색깔이 칠해진다(점점 분류될수록 한쪽은 색깔이 진해지고 한쪽은 옅어진다). 그리고 features_name은 특성의 이름을 주면 된다.

 

from sklearn.tree import plot_tree
plot_tree(dt, max_depth=1, filled=True, feature_names=['A','B','C']

 

그려 보면 나타나는 것이 지니 불순도(gini) 개념이다. 지니 불순도는 1에서 양쪽 노드가 각각 전체 노드에서 차지하는 비율을 제곱해서 빼 주면 된다. 또한 엔트로피 불순도도 있는데, 이것은 1에서  클래스 비율에 로그2(클래스비율)한 것을 모두 빼주면 된다. 정보 이득은 부모와 자식 노드 간의 불순도 차이를 말하고, 항상 정보 이득이 큰 방향으로 모델이 발전한다.

 

지니 불순도=1-(음성 클래스 비율^2+양성 클래스 비율^2)

엔트로피 불순도=1-(시그마)클래스 비율*log2(클래스 비율)

 

가치치기로 오버피팅을 제한할 때 max_depth를 건드려서 제한할 수 있고, 또 다른 걸로 min_impurity_decrease를 건드려서 제한 할 수 있다. min_impurity_decrease는 정보이득*샘플수/전체샘플수 가 특정 값 이하일때는 분할하지 않도록 하는 매개변수이다.

- 어차피 특성이 맞냐 틀리냐로 계속 판단하기 때문에 값 자체가 의미를 가지지 않는다 => 특성값을 스케일 하던 안하던 결과가 동일

- 특성 중요도 (각 특성 중에서 어떤 게 중요한지 비율로 보여줌)는 dt.feature_importances_를 사용하면 알 수 있다.

 

교차 검증과 그리드 서치

항상 궁금했던 건, 약간 어려운 코드들을 보면 항상 validation set이 있는데 왜 나는 그걸 쓰지 않냐는 거였다. 이제 알게 된 건 내가 가끔 보던 validation set검증 세트이고, 이 검증 세트는 테스트 세트와는 살짝 다르게 하이퍼파라미터(사용자가 직접 조절 가능한 변수들)을 최적화한다는 것이었다. 

 

교차 검증은 훈련 세트에서 떼온 검증 세트를 고정시켜서 한번만 모델을 학습시키는 게 아니라 n등분하여 한번씩 돌아가면서 검증 세트를 해볼 수 있도록 하는 것이다. 이렇게 하면 훈련세트에서 떼오면서 사라진 훈련세트의 양을 보완할 수 있게 된다.

 

3-폴드 교차검증 (기본미션!!!)

 

이 교차검증은 sklearn.model_selection에서 cross_validate를 임포트하면 쓸 수 있다. dt는 평가할 모델 객체, 그리고 훈련 세트를 다음 매개변수로 주면 된다. 반환값은 모델을 훈련하는데 걸린 시간과 검증하는데 걸린 시간이다. cross_validate는 디폴트로 5-폴드 교차 검증을 수행한다. cv에 숫자를 주면 (Stratified)KFold에 n_splits를 해당 숫자로 설정한 효과가 나는 것 같다. 

 

from sklearn.model_selection import cross_validate
scores=cross_validate(dt, train_input, train_target, cv=10) # 10-폴드 교차 검증

 

cross_validate는 훈련 세트를 섞어서 교차 검증을 해주지 않기 때문에 우리가 직접 분할기를 이용해서 섞어 주어야 한다. 보통 회귀 모델일 경우 KFold 분할기를 사용하고 분류 모델일 경우 StratifiedKFold를 사용한다고 한다. 이걸 cv 매개변수를 건드려서 하면 된다.

 

scores=corss_validate(dt, train_input, train_target, cv=StratifiedKFold())

 

훈련 세트를 섞고 난 다음에 10-폴드 교차 검증을 하는 코드이다. 아까 cv에 숫자를 바로 주는 거랑의 차이를 따지자면 shuffle=True로 주기 위함인 것 같다,, 안 그럼 안 섞이니까.. 약간 느낌은 splitter에서 조금 더 조건? 특징을 더 주고 그걸 cross_validate에 넣으려고 할 때 이렇게 splitter라는 변수를 만들어서 하는 게 아닐까 하는 생각이다. 교차 검증이 끝나면 전체 훈련 세트로 모델을 다시 만들어야 한다!!!!

 

splitter=StratifiedKFold(n_splits=10, shuffle=True)
scores=cross_validate(dt, train_input, train_target, cv=splitter)

 

그럼 하이퍼파라미터 튜닝은 어떻게 해야할까?

트리 모델에서 중요한 점은 하나의 매개변수가 최적 값일 때 나머지 것들도 최적 값일 보장이 안 되어 있다는 것이다. 따라서 여러 개의 값을 동시에 적당히 조절해 가면서 해야 한다. 그래서 GridSearchCV가 나왔다. 이 함수는 하이퍼파라미터 탐색과 교차 검증을 동시에 해 주기 때문에 이 함수를 쓰면 cross_validate를 쓰지 않아도 된다. 

쓰는 방법은 param이라는 파라미터를 담은 변수를 만들어서 GridSearchCV에 전달해주면 된다. .각 parameter에 대해 모델을 실행해보는데, 여기서 5-폴드 교차 검증을 또 수행하므로(기본값) 결국 5*5번의 모델 훈련이 이루어진다. n_jobs는 cpu 코어 수를 말하고 -1은 모든 cpu를 다 쓰라는 이야기이다.

 

from sklearn.model_selection import GridSearchCV
params={'min_impurity_decrease':[0.0001, 0.0002, 0.0003, 0.0004, 0.0005]} # 다섯개

gs=GridSearchCV(DecisionTreeClassifier(), params, n_jobs=-1)

 

GridSearchCV는 마지막에 최적의 하이퍼파라미터값으로 전체 훈련을 다시 한번 시켜줘야 하는 수고로움을 덜어준다 (자기가 이미 다 해준다). 그리고 최적의 모델은 gs.best_estimator_에 저장되어 있고, 최적의 매개변수 조합은 best_param_에 저장되어 있다. best_param_과 동일한 값을 뱉는 건 gs.cv_results_['params'][np.argmax(gs.cv_results_['mean_test_score'])] 이다. cv_results_속성의 mean_teset_score에는 각 매개변수에서 수행한 모델의 평균 점수가 들어 있고, params에는 수행한 파라미터가 들어있다.

 

gs.best_estimator_
gs.best_params_

gs.cv_results_['mean_test_score']

# gs.best_params_와 동일
best_index=np.argmax(gs.cv_results_['mean_test_score'])
gs.cv_results_['params'][best_index]

 

param은 보통 np.arange나 np.range를 써서 여러 개를 모두 다 하나씩 타이핑할 수고를 던다. 이렇게 하면 너무 많은 매개변수 값을 테스트해야 하기 때문에 오래 걸린다. 따라서 np.arange 대신 랜덤 서치를 이용한다. 난수 발생기와 비슷하고, 범위 내에서 어느 정도 고르게 추출하도록 한다. 

 

params={'min_impurity_decrease':np.arange(0.0001, 0.001, 0.0001),
		'max_depth':range(5, 20, 1),
        'min_samples_split':range(2, 100, 10)
        }
        
# 이걸 랜덤 서치를 이용해 다음과 같이 바꾼다
from scipy.stats import uniform, randint

params={'min_impurity_decrease':uniform(0.0001, 0.001),
		'max_depth': randint(20, 50),
        'min_samples_split':randint(2,25),
        'max_samples_split':randint(1,25),
        }

 

랜덤 서치를 이용하면 함수도 RandomizedSearchCV로 바뀌어야 한다. 매개변수 범위에서 n_iters 만큼의 교차 검증을 수행하여 최적의 매개변수 조합을 찾는 것이다.

from sklearn.model_selection import RandomizedSearchCV
gs=RandomizedSearchCV(DecisionTreeClassifier(), params,
						n_iter=100, n_jobs=-1)
gs.fit(train_input, train_target)

 

트리의 앙상블

 

05_트리_알고리즘.ipynb

Colaboratory notebook

colab.research.google.com

정형 데이터 - 엑셀 파일처럼 정형화된 데이터

비정형 데이터 - 엑셀로 표현하기 어려운 데이터. 텍스트 데이터, 사진, 음악 등.

 

정형 데이터에서는 앙상블 학습이 굉장히 효과적이다.

1. 랜덤 포레스트

결정 트리를 랜덤하게 만든다. 훈련 데이터에서 랜덤하게 샘플을 추출하여 훈련 데이터를 만들고, 중복을 허용한다. 이렇게 생긴 샘플은 부트스트랩 샘플이라고 한다. RandomizedForestClassifier는 전체 특성 수의 제곱근만큼의 특성을 랜덤하게 선택하여 훈련시킨다.

 

from sklearn.model_selection import cross_validate
from sklearn.ensemble import RandomizedForestClassifier
rf=RandomizedForestClassifier(n_jobs=-1)
scores=cross_validate(rf, train_input, train_target,
						return_train_score=True, n_jobs=-1)

 

랜덤 포레스트에서 부트스트랩 샘플을 만들었을 때 포함되지 않는 샘플을 OOB(out of bag) 샘플이라고 하고, 이것을 통해서 점수를 얻을 수 있다. 

 

rf=RandomForestClassifier(oob_score=True, n_jobs=-1)
rf.fit(train_input, train_target)
print(rf.oob_score_)

 

2. 엑스트라 트리

랜덤 포레스트오 차이점이 부트스트랩 샘플을 사용하지 않고 전체 훈련 세트를 사용한다는 것이다. 그리고 최적의 분할을 하는 것이 아니라 무작위로 분할한다.

 

from sklearn.ensemble import ExtraTressClassifier
et=ExtraTreesClassifier(n_jobs=-1)
scores=cross_validate(et, train_input, train_target,
					return_train_score=True, n_jobs=-1)

 

3. 그레디언트 부스팅

깊이가 얕은 결정 트리로 이전 트리를 보완해나간다. 경사 하강법을 이용한다. 과대적합에 강하다!

 

from sklearn.ensemble import GradientBosstingClassifier
gb=GradientBosstingClassifier(n_estimatores=500, learning_rate=0.2)
scores=cross_validate(gb, train_input, train_target,
					return_train_score=True, n_jobs=-1)

 

4. 히스토그램 기반 그레이디언트 부스팅

정형 데이터에서 가장 인기가 좋은 머신러닝 알고리즘이다. 입력 특성을 256개로 나눈다.

 

from sklearn.experimental import enable_hist_gradient_boosting
from sklearn.ensemble import HistGradientBoostingClassifier
hgb=HistGradientBoostingClassifier()
scores=cross_validate(hgb, train_input, train_target,
					return_train_score=True)

 

permutation_importance()함수는 특성을 랜덤하게 섞어서 모델 성능 변화가 어떻게 나타나는지 관찰하여 어떤 특성이 중요한지를 계산해준다. 비율로 알려준다!

result=permutation_importance(hgb, train_input, train_target,
							n_repeats=10, n_jobs=-1)

 

이 외에도 XGBoost(XGBClassifier)와, LightGbM(LGBMClassifier)도 사용한다.

'deeplearning' 카테고리의 다른 글

혼공머신 6주차 (+pytorch keras 비교)  (0) 2021.08.15
혼공머신 5주차  (0) 2021.08.09
혼공머신 3주차  (0) 2021.07.25
혼공머신 2주차  (0) 2021.07.19
혼공머신 1주차  (0) 2021.07.11