어떠한 한 현상에 대한 답을 얻는다고 가정해보자, 많은 경우에 한 명의 전문가보다 여려 명의 일반인들의 의견이 더 나은 경우가 있다.
어떻게 약한 학습기가 강한 학습기가 되어서 더 좋은 성능을 낼 수 있을까?, 이 질문은 "큰 수의 법칙"으로 설명될 수 있다.
from sklearn.datasets import load_iris from sklearn.ensemble import RandomForestClassifier,VotingClassifier from sklearn.linear_model import LogisticRegression from sklearn.svm import SVC from sklearn.metrics import accuracy_score from sklearn.model_selection import train_test_split # 데이터셋 로드 iris = load_iris() X = iris.data[:,2:] # 꽃잎의 길이, 너비 Y = iris.target x_train,x_test,y_train,y_test = train_test_split(X,Y,test_size=0.3,random_state=2021,shuffle=True) # 약한 학습기 구축 log_model = LogisticRegression() rnd_model = RandomForestClassifier() svm_model = SVC() # 앙상블 모델 구축 # 만약에 모든 모델이 predict_proba() 메서드가 있으면, 예측의 평균을 내어 soft voting(간접 투표)도 할수 있다. # 간접 투표 방식은 확률이 높은 투표에 비중을 두기 때문에 성능이 더 높다. (voting='soft' 사용) # svc는 기본적으로 predict_proba를 제공하지 않아, probability = True 지정 해야 사용 가능 # 대신 svc에서 probability = True를 지정하면 교차 검증을 사용해서 확률을 추정하기 때문에 훈련 속도 느려짐 # 대신 성능을 올라감 voting_model = VotingClassifier( estimators=[('lr',log_model),('rf',rnd_model),('svc',svm_model)], # 3개의 약한 학습기 voting='hard' # 직접 투표(hard voting) ) # 앙상블 모델 학습 voting_model.fit(x_train,y_train) # 모델 비교 for model in (log_model,rnd_model,svm_model,voting_model): model.fit(x_train,y_train) y_pred = model.predict(x_test) print(model.__class__.__name__," : ",accuracy_score(y_test,y_pred)) > LogisticRegression : 1.0 RandomForestClassifier : 0.9555555555555556 SVC : 1.0 VotingClassifier : 1.0
1. 사이킷런의 배깅과 페이스팅
from sklearn.ensemble import BaggingClassifier from sklearn.tree import DecisionTreeClassifier # 모델 구축 # BaggingClassifier에서 사용한 분류기가 클래스 확률추정(predict_proba)이 가능하면 자동으로 간접 투표 사용 bag_model = BaggingClassifier( DecisionTreeClassifier(), # 약한 학습기(결정 트리) n_estimators=500, # 약한 학습기(결정 트리) 500개 생성 max_samples=0.05, # 0.0~1.0 사이 실수 선택(실수 x 샘플 수) 혹은 샘플수 지정 bootstrap=True, # True : 배깅, False : 페이스팅 n_jobs=-1 # 훈련과 예측에 사용할 CPU 코어 수 (-1 : 가용한 모든 코어 사용) ) # 모델 학습 bag_model.fit(x_train,y_train) # 모델 예측 y_pred = bag_model.predict(x_test) # 모델 평가 print(bag_model.__class__.__name__," : ",accuracy_score(y_test,y_pred)) > BaggingClassifier : 0.9777777777777777
2. oob 평가
# 모델 구축 bag_model = BaggingClassifier( base_estimator = DecisionTreeClassifier(), n_estimators = 500, bootstrap = True, n_jobs = -1, oob_score = True # oob평가를 위해 True를 지정한다. ) # 모델 학습 bag_model.fit(x_train,y_train) # 모델 평가(oob_score_) print('oob_score : ',bag_model.oob_score_) # 모델 평가 y_pred = bag_model.predict(x_test) print('test_score : ',accuracy_score(y_test,y_pred)) >oob_score : 0.9523809523809523 test_score : 0.9333333333333333
from sklearn.ensemble import RandomForestClassifier # 랜덤포레스트 모델 구축 rnd_model = RandomForestClassifier( n_estimators = 500, # 예측기 500개 max_leaf_nodes = 16, # 자식노드의 최대 개수 n_jobs = -1 # CPU 코어 구동 개수 ) # 모델 학습 rnd_model.fit(x_train,y_train) # 모델 예측 y_pred_rf = rnd_model.predict(x_test) # 모델 평가 print("rnd_model : ",accuracy_score(y_pred_rf,y_test)) > rnd_model : 0.9333333333333333
1. 엑스트라 트리
2. 특성 중요도
# 데이터셋 정의 x = iris.data[:,:] y = iris.target # 모델 구축 rnd_model = RandomForestClassifier( n_estimators = 500, n_jobs = -1 ) # 모델 학습 rnd_model.fit(x,y) # 특성 중요도 확인 (전체 특성 중요도 합 : 1) for feature_name,feature_imp in zip(iris['feature_names'],rnd_model.feature_importances_): print(feature_name,' : ',feature_imp) > sepal length (cm) : 0.09919561404019304 sepal width (cm) : 0.02374662557128492 petal length (cm) : 0.4544515575221269 petal width (cm) : 0.42260620286639516
from sklearn.ensemble import AdaBoostClassifier from sklearn.tree import DecisionTreeClassifier # 아다부스트 모델 구축 # 아다부스트의 학습기 : Decision Tree (max_depth =1) 사용 # 학습기 개수(n_estimators) : 200개 # SAMME(Stagewise Additive Modeling using a Multiclass Exponential loss function) 알고리즘 사용 # 기본 학습기가 확률 추정(predict_proba)이 가능하면 SAMME.R 사용 -> 일반적으로 성능이 더 좋음 ada_model = AdaBoostClassifier( DecisionTreeClassifier(max_depth=1), n_estimators = 200, algorithm = 'SAMME.R', learning_rate=0.5 ) # 모델 학습 ada_model.fit(x,y)
from sklearn.tree import DecisionTreeRegressor # 결정트리(max_depth=3) 모델 구축 및 학습 tree_reg_model_1 = DecisionTreeRegressor(max_depth=3) tree_reg_model_1.fit(x,y) # 첫 번째 학습기에서 발생한 잔차를 목적함수로 모델 학습 residual_1 = y - tree_reg_model_1.predict(x) tree_reg_model_2 = DecisionTreeRegressor(max_depth=3) tree_reg_model_2.fit(x,residual_1) # 두 번째 학습기에서 발생한 잔차를 목적함수로 모델 학습 residual_2 = y - tree_reg_model_2.predict(x) tree_reg_model_3 = DecisionTreeRegressor(max_depth=3) tree_reg_model_3.fit(x,residual_2) # 새로운 데이터를 세 개의 트리를 포함한 앙상블 모델로 예측 x_new = [[1.4,0.2]] prediction = sum(tree.predict(x_new) for tree in [tree_reg_model_1,tree_reg_model_2,tree_reg_model_3]) prediction > array([-5.20417043e-18])
# 사이킷런에서 제공하는 GBRT 앙상블을 다음과 같이 간단하게 훈련시킬 수 있다. from sklearn.ensemble import GradientBoostingRegressor # GBRT 모형 구축 # GBRT 앙상블 모형도 마찬가지로 n_estimators, max_depth, min_samples_leaf 등을 통해 모델 규제가 가능하다. # 추가적으로 learning_rate가 각 트리의 기여 정도를 조절한다. # learning_rate가 0.1보다 낮게 설정되면 훈련을 위한 트리가 더 많이 필요하지만 성능은 좋아진다. # 이러한 방식을 축소(shrinkage)라고 부르는 규제 방법이다. gbrt = GradientBoostingRegressor(max_depth = 3, n_estimators = 3, learning_rate = 1) # GBRT 모형 학습 gbrt.fit(x,y)
# 최적의 estimators수를 찾기 위한 간단한 방법 import numpy as np from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error # train set과 validation set을 8:2로 분리 x_train, x_val, y_train, y_val = train_test_split(x,y,test_size=0.2) # GBRT(max_depth=3,예측기 수=120) 모형 구축 gbrt = GradientBoostingRegressor(max_depth=3, n_estimators=120) # GBRT 모형 학습 gbrt.fit(x_train,y_train) # staged_predict를 활용하여 훈련 각 단계에서 앙상블에 의해 만들어진 예측을 반복자로 반환 errors = [mean_squared_error(y_val,y_pred) for y_pred in gbrt.staged_predict(x_val)] # validation 검증 결과에서 가장 좋은 성능을 보인 예측기 수를 추출 bst_estimators_num = np.argmin(errors) # 최고의 일반화 성능을 가진 하이퍼파라미터(n_estimators)를 가지고 재 모델 구축 print("best_est_num : ",bst_estimators_num) gbrt_best = GradientBoostingRegressor(max_depth=3,n_estimators=bst_estimators_num) # 데이터셋(train + valid)를 가지고 학습 gbrt_best.fit(x,y) -------------------------------------------------------------------- 조기종료(early stopping)를 활용한 # warm_start : fit 메서드 호출될 때마다 기존 트리 유지 및 훈련 추가할 수 있게 해줌 # subsample : 각 트리는 무작위로 선택된 25% 훈련 샘플로 학습 => 편향 상승 => 분산 감소 => 훈련 속도 상승 # 위 subsample 방법을 "확률적 그래디언트 부스팅"이라 부른다. gbrt = GradientBoostingRegressor(max_depth=3, warm_start=True,subsample=0.25) min_val_error = float('inf') error_going_up = 0 best_estimator = 0 for n_estimators in range(1,120): gbrt.n_estimators = n_estimators gbrt.fit(x_train,y_train) y_pred = gbrt.predict(x_val) val_error = mean_squared_error(y_val, y_pred) if val_error < min_val_error: min_val_error = val_error best_estimator = n_estimators error_going_up = 0 else: error_going_up += 1 # 성능 향상이 되지 않을 때마다 +1 if error_going_up == 5: break # 성능 향상 연속 5회 : 조기 종료
지금까지 머신러닝을 배우기 위한 대부분의 기본 개념을 익혀보았다. 물론 모든 챕터의 개념을 세세하게 리딩한 것은 아니나, 지금까지의 내용을 토대로 각 모델에 대한 개념을 깊게 공부해본다면 지금보다 더 깊은 이해할 가질 수 있게 될 것이다. 다음 시간에는 머신러닝의 최신 알고리즘을 활용하여 kaggle 데이터 분석 및 예측을 해보는 시간을 가질 것이다.
감사합니다. 친절하고 깔끔한 안내로 많이 배웠습니다. 따라 배우다 아래와 같이 오류가 나서 문의 올립니다. ㅠㅠ 열심히 배우고 싶은데 이 부분에서 막혀 더 못나아가고 있습니다. ㅠㅠ
x_new = [[1.4,0.2]]
prediction = sum(tree.predict(x_new) for tree in [tree_reg_model_1,tree_reg_model_2,tree_reg_model_3])
prediction
ValueError Traceback (most recent call last)
in ()
1 x_new = [[1.4,0.2]]
----> 2 prediction = sum(tree.predict(x_new) for tree in [tree_reg_model_1,tree_reg_model_2,tree_reg_model_3])
3 prediction
4 frames
/usr/local/lib/python3.7/dist-packages/sklearn/base.py in check_n_features(self, X, reset)
399 if n_features != self.n_features_in:
400 raise ValueError(
--> 401 f"X has {nfeatures} features, but {self.class.name} "
402 f"is expecting {self.n_features_in} features as input."
403 )
ValueError: X has 2 features, but DecisionTreeRegressor is expecting 4 features as input.