📗강의노트/핸즈온 머신러닝

[핸즈온 머신러닝] 제 7장 연습문제 풀이

728x90
반응형

Exercise Part. 6

Ensemble_learning and random forests

1. 정확히 같은 훈련 데이터로 다섯 개의 다른 모델을 훈련시켜서 모두 95%의 정확도를 얻었다면 이 모델들을 연결하여 더 좋은 결과를 얻을 수 있을까요? 가능하다면 어떻게 해야 할 까요? 그렇지 않다면 왜일까요?

앙상블을 만들어 더 나은 결과를 기대할 수 있다. 모델이 서로 다르다면 더 좋다. 그리고 다른 훈련 샘플에서 훈련되었다면 더더욱 좋다. ( 배깅 / 페이스팅의 핵심 ). 그렇지 않아도 모델이 서로 많이 다르면 여전히 좋은 결과를 냄!

2. 직접 투표와 간접 투표 분류기 사이의 차이점은 무엇일까요?

직접 투표 분류기는 횟수를 중요시하여, 가장 많은 투표를 얻은 클래스를 선택. (다수결)

간접 투표 분류기는 각 클래스의 평균적인 확률 추정값을 계산해서 가장 높은 확률을 가진 클래스를 고름. 이 방법은 신뢰가 높은 투표에 더 가중치를 주고 종종 더 나은 성능을 낸다. 하지만 앙상블에 있는 모든 분류기가 클래스 확률을 추정할 수 있어야 사용 가능!

3. 배깅 앙상블의 훈련을 여러 대의 서버에 분산시켜 속도를 높일 수 있을까요? 페이스팅 앙상블, 부스팅 앙상블, 랜덤 포레스트, 스태킹 앙상블의 경우는 어떨까요?

배깅 앙상블의 각 예측기는 독립적이므로 여러 대의 서버에 분산하여 앙상블의 훈련 속도를 높일 수 있다. 페이스팅, 랜덤 포레스트도 마찬가지.

하지만 부스팅 앙상블의 예측기는 이전 예측기를 기반으로 만들어지기 때문에 훈련이 순차적이어야하고, 여러 대의 서버에 분산해서 얻을 수 있는 이득이 없다.

스태킹 앙상블의 경우 한 층의 모든 예측기가 각각 독립적이므로 여러대의 서버에서 병렬로 훈련될 수 있다. 하지만 한 층에 있는 예측기들은 이전 층의 예측기들이 훈련된 후에 훈련될 수 있다.

4. oob 평가의 장점은 무엇인가요?

배깅 앙상블의 각 예측기가 훈련에 포함되지 않은 샘플을 사용해 평가된다. 이는 추가적인 검증 세트가 없어도 편향되지 않게 앙상블을 평가하도록 도와준다. 그러므로 훈련에 더 많은 샘플을 사용할 수 있어서 앙상블의 성능은 조금 더 향상 될 것.

5. 무엇이 엑스트라 트리를 일반 랜덤 포레스트보다 더 무작위하게 만드나요? 추가적인 무작위성이 어떻게 도움이 될까요? 엑스트라 트리는 일반 랜덤 포레스트보다 느릴까요, 빠를까요?

랜덤 포레스트에서 트리가 성장할 때 각 노드에서 특성의 일부를 무작위로 선택해 분할에 사용한다. 가능한 최선의 임계점을 찾는게 아니라, 각 특성에 대해 랜덤한 임계점을 사용한다, 이 추가적인 무작위성은 규제처럼 작동한다. 즉 랜포가 과대적합이라면 엑스트라는 X. 가능한 최선의 임계점을 찾는게 아니라 랜포보다 훈련이 더 빠르다. 그러나 예측을 할 때는 랜덤 포레스트 보다 더 빠르지도 느리지도 않다.

6. 아다부스트 앙상블이 훈련 데이터에 과소적합되었다면 어떤 매개변수를 어떻게 바꾸어야 할까요?

예측기의 수를 증가시키거나, 기반 예측기의 규제 하이퍼파라미터를 감소시켜 볼 수 있다. 또한 학습률을 약간 증가시켜 볼 수 있다.

7. 그래디언트 부스팅 앙상블이 훈련 데이터에 과대적합되었다면 학습률을 높여야 할까요, 낮춰야 할까요?

학습률을 감소시켜야한다 ( 예측기 수가 너무 많으면 ) 알맞은 개수를 찾기 위해 조기 종료 기법을 사용할 수 있다.

8. MNIST 데이터를 훈련 ,검증, 테스트 데이터로 나눈다. ( 훈련 : 40,000 / 검증 : 10,000 / 테스트 : 10,000 ) 그 다음 랜덤 포레스트 분류기, 엑스트라 트리 분류기, SVM 같은 여러 종류의 분류기를 훈련. 그리고 검증 세트에서 개개의 분류기보다 더 높은 성능을 내도록 간접 or 직접 투표 분류기를 사용하는 앙상블로 연결해보세요. 앙상블을 얻고 나면 테스트 세트로 확인해보세요. 개개의 분류기와 비교해서 성능이 얼마나 향상되나요?

In [1]:
from sklearn.datasets import fetch_openml
mnist = fetch_openml('mnist_784',version=1)
In [2]:
from sklearn.model_selection import train_test_split

X_train_val, X_test, y_train_val, y_test = train_test_split(mnist.data,mnist.target
                                                            ,test_size=10000, random_state=42)
X_train,X_val,y_train,y_val = train_test_split(X_train_val,y_train_val,test_size=10000,
                                              random_state=42)
In [3]:
from sklearn.ensemble import RandomForestClassifier, ExtraTreesClassifier
from sklearn.svm import LinearSVC
from sklearn.neural_network import MLPClassifier
In [4]:
rnd_clf = RandomForestClassifier(n_estimators=10,random_state=42)
ext_clf = ExtraTreesClassifier(n_estimators=10, random_state=42)
svm_clf = LinearSVC(max_iter=10000,random_state=42)
mlp_clf = MLPClassifier(random_state=42)
In [5]:
# 검증 세트에서의 성능 확인
from sklearn.metrics import accuracy_score
In [7]:
# 한 번에 훈련
models = [rnd_clf,ext_clf,svm_clf,mlp_clf]

for model in models:
    print("훈련 :",model)
    model.fit(X_train,y_train)
훈련 : RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=None, max_features='auto', max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=2,
            min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=None,
            oob_score=False, random_state=42, verbose=0, warm_start=False)
훈련 : ExtraTreesClassifier(bootstrap=False, class_weight=None, criterion='gini',
           max_depth=None, max_features='auto', max_leaf_nodes=None,
           min_impurity_decrease=0.0, min_impurity_split=None,
           min_samples_leaf=1, min_samples_split=2,
           min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=None,
           oob_score=False, random_state=42, verbose=0, warm_start=False)
훈련 : LinearSVC(C=1.0, class_weight=None, dual=True, fit_intercept=True,
     intercept_scaling=1, loss='squared_hinge', max_iter=10000,
     multi_class='ovr', penalty='l2', random_state=42, tol=0.0001,
     verbose=0)
/Users/charming/anaconda3/lib/python3.7/site-packages/sklearn/svm/base.py:931: ConvergenceWarning: Liblinear failed to converge, increase the number of iterations.
  "the number of iterations.", ConvergenceWarning)
훈련 : MLPClassifier(activation='relu', alpha=0.0001, batch_size='auto', beta_1=0.9,
       beta_2=0.999, early_stopping=False, epsilon=1e-08,
       hidden_layer_sizes=(100,), learning_rate='constant',
       learning_rate_init=0.001, max_iter=200, momentum=0.9,
       n_iter_no_change=10, nesterovs_momentum=True, power_t=0.5,
       random_state=42, shuffle=True, solver='adam', tol=0.0001,
       validation_fraction=0.1, verbose=False, warm_start=False)
In [12]:
# 한 번에 검증

for model in models:
    y_pred = model.predict(X_val)
    print("정확도 :",accuracy_score(y_val,y_pred))
정확도 : 0.9469
정확도 : 0.9492
정확도 : 0.8502
정확도 : 0.9663
In [29]:
# 투표
from sklearn.ensemble import VotingClassifier

named_models = [
    ("RandomForest" , rnd_clf),
    ("ExtraTree" , ext_clf),
    ("LinearSVM" , svm_clf),
    ("MLP" , mlp_clf),
]
In [30]:
voting_clf = VotingClassifier(named_models)
In [31]:
voting_clf.fit(X_train,y_train)
/Users/charming/anaconda3/lib/python3.7/site-packages/sklearn/svm/base.py:931: ConvergenceWarning: Liblinear failed to converge, increase the number of iterations.
  "the number of iterations.", ConvergenceWarning)
Out[31]:
VotingClassifier(estimators=[('RandomForest', RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=None, max_features='auto', max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=2,
        ...=True, solver='adam', tol=0.0001,
       validation_fraction=0.1, verbose=False, warm_start=False))],
         flatten_transform=None, n_jobs=None, voting='hard', weights=None)
In [32]:
voting_clf.score(X_val,y_val)
Out[32]:
0.9587
In [33]:
[model.score for model in voting_clf.estimators_ ]
Out[33]:
[<bound method ClassifierMixin.score of RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
             max_depth=None, max_features='auto', max_leaf_nodes=None,
             min_impurity_decrease=0.0, min_impurity_split=None,
             min_samples_leaf=1, min_samples_split=2,
             min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=None,
             oob_score=False, random_state=42, verbose=0, warm_start=False)>,
 <bound method ClassifierMixin.score of ExtraTreesClassifier(bootstrap=False, class_weight=None, criterion='gini',
            max_depth=None, max_features='auto', max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=2,
            min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=None,
            oob_score=False, random_state=42, verbose=0, warm_start=False)>,
 <bound method ClassifierMixin.score of LinearSVC(C=1.0, class_weight=None, dual=True, fit_intercept=True,
      intercept_scaling=1, loss='squared_hinge', max_iter=10000,
      multi_class='ovr', penalty='l2', random_state=42, tol=0.0001,
      verbose=0)>,
 <bound method ClassifierMixin.score of MLPClassifier(activation='relu', alpha=0.0001, batch_size='auto', beta_1=0.9,
        beta_2=0.999, early_stopping=False, epsilon=1e-08,
        hidden_layer_sizes=(100,), learning_rate='constant',
        learning_rate_init=0.001, max_iter=200, momentum=0.9,
        n_iter_no_change=10, nesterovs_momentum=True, power_t=0.5,
        random_state=42, shuffle=True, solver='adam', tol=0.0001,
        validation_fraction=0.1, verbose=False, warm_start=False)>]
In [41]:
# SVM제거
voting_clf.set_params(LinearSVM=None)
Out[41]:
VotingClassifier(estimators=[('RandomForest', RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=None, max_features='auto', max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=2,
        ...=True, solver='adam', tol=0.0001,
       validation_fraction=0.1, verbose=False, warm_start=False))],
         flatten_transform=None, n_jobs=None, voting='hard', weights=None)
In [42]:
voting_clf.estimators_
Out[42]:
[RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
             max_depth=None, max_features='auto', max_leaf_nodes=None,
             min_impurity_decrease=0.0, min_impurity_split=None,
             min_samples_leaf=1, min_samples_split=2,
             min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=None,
             oob_score=False, random_state=42, verbose=0, warm_start=False),
 ExtraTreesClassifier(bootstrap=False, class_weight=None, criterion='gini',
            max_depth=None, max_features='auto', max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=2,
            min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=None,
            oob_score=False, random_state=42, verbose=0, warm_start=False),
 LinearSVC(C=1.0, class_weight=None, dual=True, fit_intercept=True,
      intercept_scaling=1, loss='squared_hinge', max_iter=10000,
      multi_class='ovr', penalty='l2', random_state=42, tol=0.0001,
      verbose=0),
 MLPClassifier(activation='relu', alpha=0.0001, batch_size='auto', beta_1=0.9,
        beta_2=0.999, early_stopping=False, epsilon=1e-08,
        hidden_layer_sizes=(100,), learning_rate='constant',
        learning_rate_init=0.001, max_iter=200, momentum=0.9,
        n_iter_no_change=10, nesterovs_momentum=True, power_t=0.5,
        random_state=42, shuffle=True, solver='adam', tol=0.0001,
        validation_fraction=0.1, verbose=False, warm_start=False)]
In [43]:
# 안지워져서 다시
del voting_clf.estimators_[2]
In [44]:
voting_clf.score(X_val,y_val)
Out[44]:
0.9649
In [45]:
# SVM이 성능 저하 시킨 것. 
In [46]:
# 간접투표 
# 이미 훈련 시켰으니 Hard -> soft 바꾸기

voting_clf.voting = 'soft'
In [47]:
# 다시 재평가
voting_clf.score(X_val,y_val)
Out[47]:
0.9715
In [49]:
# 개개의 분류기보다 낫다
voting_clf.score(X_test,y_test)
Out[49]:
0.9693
In [50]:
[model.score(X_test,y_test) for model in voting_clf.estimators_]
Out[50]:
[0.0, 0.0, 0.0]

9. 이전 연습문제의 각 분류기를 실행해서 검증 세트에서 예측을 만들고 그 결과로 새로운 훈련 세트를 만들어보라. 각 훈련 샘플은 하나의 이미지에 대한 전체 분류기의 예측을 담은 벡터고 타깃을 이미지 클래스. 새로운 훈련 세트에 분류기 하나를 훈련시켜봐라. 방금 블렌더를 훈련시킨것이다. 그리고 이 분류기를 모아서 스태킹 앙상블을 구성했다. 이제 테스트 세트에 앙상블을 평가해보라. 테스트 세트의 각 이미지에 대해 모든 분류기로 예측을 만들고 앙상블의 예측 결과를 만들기 위해 블렌더에 그 예측을 주입한다. 앞서 만든 투표 분류기와 비교하면 어떤가?

In [51]:
import numpy as np
X_val_pred = np.empty((len(X_val), len(models)), dtype=np.float32)
In [52]:
for i, model in enumerate(models):
    X_val_pred[:,i] = model.predict(X_val)
In [53]:
X_val_pred
Out[53]:
array([[5., 5., 5., 5.],
       [8., 8., 8., 8.],
       [2., 2., 2., 2.],
       ...,
       [7., 7., 7., 7.],
       [6., 6., 6., 6.],
       [7., 7., 7., 7.]], dtype=float32)
In [54]:
rnd_forest_blender = RandomForestClassifier(n_estimators=200,oob_score=True,random_state=42)
rnd_forest_blender.fit(X_val_pred,y_val)
Out[54]:
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=None, max_features='auto', max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=2,
            min_weight_fraction_leaf=0.0, n_estimators=200, n_jobs=None,
            oob_score=True, random_state=42, verbose=0, warm_start=False)
In [55]:
rnd_forest_blender.oob_score_
Out[55]:
0.9601
In [63]:
X_test_pred = np.empty((len(X_test), len(models)), dtype=np.float32)

for i, model in enumerate(models):
    X_test_pred[:,i] = model.predict(X_test)  # 각 리스트에서 i열만 뽑아내기 
In [83]:
y_pred = rnd_forest_blender.predict(X_test_pred)
In [84]:
accuracy_score(y_test,y_pred)
Out[84]:
0.9628

앞서 만든 간접 투표 분류기 보다는 좋진 않지만 개개의 분류기보다는 당연히 좋다!


728x90
반응형