random forest의 boost모델의 일종이다.
잠깐 ! 부스트와 배깅 중 어떤 것을 어떤 환경에서 사용해야 할까? → 부스팅은 오답에 집중하기 때문에 error가 작다. 따라서 속도가 느리고 과적합의 위험이 있다. 성능을 높이고 싶다면 부스팅, 과적합이 문제라면 배깅을 선택하는 것이 좋다.
잠깐 ! 스태깅은 뭘까? → 모델들이 예측한 결과를 다시 훈련세트로 활용하는 방법이다. 이 방법은 예측값이 다시 input 데이터로 활용되기 때문에 과적합의 위험이 크다.
Stacking
•
OOF (Out of fold)
위의 사진이 oof의 과정을 나타낸 것이다. 그림에서는 5개의 모델(n_estimators)을 사용하고 있는데 크게 다음의 과정을 거친다.
1.
학습 데이터에서 cross-validation 을 k번 진행하면 k개의 prediction값이 출력된다.
2.
prediction값들을 다음 모델의 input 데이터로 사용한다.
3.
최종 모델은 k개의 prediction값을 받아 값을 예측하고 최종 결과를 도출한다.
간단(?)하게 oof 과정을 코드로 구현
# 각 모델마다 oof 적용
def get_oof(clf, x_train, y_train, x_test):
oof_train = np.zeros((n_train,))
oof_test = np.zeros((n_test,))
oof_test_skf = np.empty((NFOLDS,n_test))
# 각 모델마다 cross-validation 반복
for i, (train_index,test_index) in enumerate(kf.split(train)):
x_tr = x_train[train_index]
y_tr = y_train[train_index]
x_ts = x_train[test_index]
clf.train(x_tr, y_tr)
oof_train[test_index] = clf.predict(x_ts)
oof_test_skf[i,:] = clf.predict(x_test)
oof_test[:] = oof_test_skf.mean(axis=0)
return oof_train.reshape(-1, 1), oof_test.reshape(-1, 1)
# oof prediction 실행
et_oof_train, et_oof_test = get_oof(et, x_train, y_train, x_test) # extra tree
rf_oof_train, rf_oof_test = get_oof(rf,x_train, y_train, x_test) # Random Forest
ada_oof_train, ada_oof_test = get_oof(ada, x_train, y_train, x_test) # AdaBoost
gb_oof_train, gb_oof_test = get_oof(gb,x_train, y_train, x_test) # Gradient Boost
svc_oof_train, svc_oof_test = get_oof(svc,x_train, y_train, x_test) # Support Vector Classifier
# 5개의 prediction을 모두 합치기
x_train = np.concat(( et_oof_train, rf_oof_train, ada_oof_train, gb_oof_train, svc_oof_train),axis=1)
x_test = np.concat(( et_oof_test, rf_oof_test, ada_oof_test, gb_oof_test, svc_oof_test), axis=1)
# 최종모델 xgboost의 input에는 5개의 모델 prediction만 들어있다.
gbm = xgb.XGBClassifier().fit(x_train, y_train)
predictions = gbm.predict(x_test)
Python
복사
adaboost 의 구조
한개의 노드와 두 개의 잎을 가지는 stump로 이루어져 있다. 즉, 하나의 피처로 2개의 데이터를 분류하는 구조다. 모든 stump의 가중치를 동일하게 두지 않고 다른 가중치를 두어서 stump들을 합친다.
예를들어 아래와 같은 데이터가 있다고 하자.
먼저, sample weight 는 각 샘플 모두 동일하게 1/8 이다. 레이블은 Heart Disease 다.
이제, 첫번째 stump(Chest Pain) 을 만들어보자.
Chest Pain은 Label(Hear Disease)가 'Yes' 'No' 두개로 나뉜다. Yes Heart Disease 리프를 살펴보자. Label이 Yes이고, Chest또한 Yes인 경우는 1,3,4열인 3개이다. 이렇게 리프를 채우면 하나의 stump가 만들어진다.
위의 과정을 반복하여 모든 feature(Chest Pain, Blocked Arteries, Patient Weight)에 대한 stump를 만들어보면 다음과 같다.
각 Stump의 지니 계수를 구하고, 지니 계수가 가장 작은(즉, 불평등지수가 가장 작은) stump를 개선시킨다.
Amount of Say 구하기
정보량을 수치화 하기위해 amount of say를 구해야한다.
앞서 Weight라는 feature에서 틀린 정보는 1개만 존재했고 가장 지니 계수가 낮았다.
이 stump의 total error 는 1/8 이 된다.
amount of say의 공식은 다음과 같다.
amount of say의 그래프, x = total error
total error가 0에 가까울수록 amount of say는 큰 양수값을 갖는다. total error가 1에 가까울수록 amount of say는 극단적인 음수값을 갖는다.
이 그래프의 해석은 total error 가 0에 가까우면 예측이 모두 맞는다는 말이고, 0.5라면 값이 0이기 때문에 의미 없는 모델이라고 생각하면 된다.
따라서 이 그래프를 통해 total error가 매우 작은 stump는 큰 정보량(큰 양수값)을 갖게 되고 큰 가중치를 부여받아 틀린값에 대해 깊이 학습하게 된다.
반대로, 오차가 큰 stump에 대해서는 맞은 데이터에 큰 가중치를 두게 된다.
가중치 설정
그렇다면 가중치를 어떤 값을 줘야하는 걸까? 앞서 활용한 weight가 못맞춘 데이터 1개에 대한 가중치를 구해보자.
가중치는 다음 공식을 적용하면 New Sample Weight = (1/8) * e^(0.97) = (1/8) * 2.64 = 0.33가 나온다.기존의 1/8 (=0.125)보다 훨씬 높은 결과이다.
맞춘 데이터는 지수의 분포만 바꾼 공식으로 적용하면 된다.
그 결과 새로운 weight는 기존의 weight보다 못맞춘 데이터에게 높은 weight를 주고, 맞춘 데이터에게 낮은 weight를 줬다.
→ 여기서 weight의 합이 항상 1이 되야 하기 때문에 Norm해줘 Norm-weight를 구해준다.
새로운 테이블의 생성
위의 결과를 바탕으로 새로운 테이블을 만든다. 만드는 방법은 norm_weight의 누적값을 이용해 랜덤하게 샘플링한다.
만약 랜덤 샘플링을 했을 때, 0~0.07의 값이 나오면 첫번째 데이터가, 0.07~0.14가 나오면 두번째 데이터, 0.21~0.7(0.49)이 나오면 4번째 데이터가 선택된다. 즉, weight가 가장 큰 4번째 데이터가 여러번 뽑힐 확률이 높다.
실제로 4번째 데이터가 4번이나 포함되었다. 이렇게 데이터의 가중치를 두고, 새로워진 테이블에 중복이 됨으로써 boost모델로 적용될 수 있는것이다. 이후, 만들어진 데이터로 처음부터 돌아가 반복한다.
최종 결과
결과를 보면 Label이 'Yes'인 경우(Has Heart Disease) Label ‘No’ 라고 분류한 경우보다 total amount of say가 2.7로 더 크기 때문에 Yes라고 결론을 내린다.
장점
1.
과적합의 영향을 덜 받는다.
: 결합하는 모형의 개수가 증가함에 따라 예측 오차가 잘 커지지 않는다는 장점이 있지만, 모형의 개수가 너무 많을 경우에는 큰 의미는 없다.
2.
구현이 쉽다.
3.
유연하다.
: 다양한 손실 함수를 사용할 수 있다. 기본 학습기에도 제한이 없다.(의사결정나무, 로지스틱 회귀, 선형 회귀 등등)
단점
1.
이상치에 민감하다.
2.
해석이 어렵다.
: 이런 특징은 모든 앙상블 모형들이 그러하다. 즉 입력 변수와 출력 변수간의 관계를 해석하기 어렵다.
활용
scikit-learn 의 AdaBoostClassifier 를 사용한다.
from sklearn.ensemble import AdaBoostClassifier
AdaBoostClassifier(base_estimator = None, n_estimators=50, learning_rate=1.0, random_state=None)
SQL
복사
→ 학습기의 수가 많을수록 learning_rate 은 작게 하는 것이 좋고, 학습기의 수가 적을수록 learning_rate 는 작게하는 것이 좋다.
보통은 base_estimator (결정 트리) 의 max_depth 값을 설정해준 다음 모델을 학습시킨다.
→ max_depth 의 default는 5다.