My Data Story
[모델 알고리즘][앙상블 학습] 랜덤포레스트 본문
◈ '앙상블 학습' 목차 ◈
2. 랜덤포레스트
랜덤포레스트와 엑스트라에 대해 이해하고 트리 계열 모델의 특성 중요도 산출에 대해 살펴보자.
1. 랜덤 포레스트
의사 결정 트리 모델에서 훈련 데이터의 작은 변화는 트리의 큰 변화와 결과적으로 최종 예측을 할 수 있고, 훈련 데이터에 과대 적합된 복잡한 트리르 생성할 수 있다. 복잡한 트리는 편향은 낮지만 분산은 매우 높아진다. 랜덤포레스트는 분산을 줄이는 것을 목적으로 동일한 훈련 세트의 다른 부분에 대해 여러 심층 결정 트리를 평균화한다.
랜덤포레스트는 일반적으로 배깅(또는 페이스팅)을 적용한 결정트리 앙상블로 더 나아가 sample뿐 아니라 feature도 복원 추출이 가능하다.
feature 에 대한 복원 추출 적용하는 이유는 일반 부트스트랩 샘플에서 트리간의 상관관계 때문이다. 하나 또는 몇 개의 feature가 응답 변수에 대한 매우 강력한 예측 변수인 경우, 해당 feaure는 다수의 예측기에서 선택되어 예측기 간의 상관 관계가 생길 수 있기 때문에 feature 선택에도 다양성을 부여한다.
뿐만 아니라 랜덤포레스트 알고리즘은 트리의 노드 분할할 때 전체 특성 중에서 최선의 특성을 찾는 대신 무작위로 선택한 특성의 후보 중에서 최적의 특성을 찾는 식(max_feature < 1.0)으로 무작위성을 더 주입한다. 이는 트리를 더 다양하게 만들어 편향은 손해보더라도 분산을 낮추어 더 나은 모델을 생성한다.
BaggingClassifier 에 DecisionTreeClassifier() 를 넣어 만드는 대신, 결정 트리에 최적화되어 사용하기 편리한 RandomForestClassifier 를 사용할 수 있다. 두 모델은 비슷한 결과를 도출한다.
from sklearn.ensemble import RandomForestClassifier
#랜덤포레스트 형성
rnd_clf = RandomForestClassifier(n_estimators = 500,
max_leaf_nodes = 16,
n_jobs = 1)
rnd_clf.fit(X_train, y_train)
y_pred_clf = rnd_clf.predict(X_test)
#배깅 형성
bag_clf = BaggingClassifier(DecisionTreeClassifier(),
n_estimators = 500,
max_leaf_nodes = 16,
max_samples = 1.0,
bootstrap = True,
bootstrap_feature = True,
n_jobs = 1)
bag_clf.fit(X_train, y_train)
bag_clf.predict(X_test)
2. 엑스트라 트리
엑스트라 트리는 부트스트랩 샘플이 아닌 전체 학습 샘플로 훈련 하고 트리에 더 무작위성을 부여한다.
트리를 더욱 무작위하게 만들기 위해 최적의 임계값을 찾는 대신, 후보 특성의 임의값을 사용해 무작위로 분할한 다음 그 중에서 최상의 분할을 선택한다.
랜덤포레스트보다 엑스트라 트리가 더 빠르긴 하다.
어떤 것이 더 나을 지는 예단하기 어렵기에 일반적으로 둘 다 시도해보고 교차 검증으로 비교하는 것이 유일한 방법이다.
(더불어 그리드 탐색으로 하이퍼파라미터 튜닝도 함께 해야 한다.)
3. 특성 중요도
결정 트리 기반의 모델은 특성 중요도를 제공한다.
DecisionTreeClassifier의 특성 중요도는 일부 특성을 완전히 배제시기키지만, 랜덤포레스트의 특성 중요도는 거의 모든 특성에 대해 평가할 기회를 갖는다.
사이킷런에서 트리계열 모델은 어떤 특성을 사용한 노드가 (랜덤 포레스트에 있는 모든 트리에 걸쳐서) 평균적으로 불순도를 얼마나 감소시키는 확인하여 특성 중요도를 측정한다.
step1
훈련이 끝난 뒤 각 트리 별로 특성 중요도를 계산한다.
이때 모델을 충분히 훈련시킨 후 테스트 세트에서 적절한 일반화 모델이 생성된 경우 특성 중요도를 계산한다.
적절하지 않은 모델에서 특성 중요도를 계산하는 것은 의미가 없기 때문이다.
step2
특성 별로 각 결정 트리에서의 특성 중요도를 모두 더한 후 트리 수로 나눠 정규화한다.
step3
이 값은 feature_importances_ 에 저장된다.
from sklearn.datasets import load_iris
iris = load_iris()
rnd_clf = RandomForestClassifier(n_estimators=500, n_jobs=1)
rnd_clf.fit(iris.data, iris.targets)
for name, score in zip(iris.feature_names, rnd_clf.feature_importances_) :
print(name, score)
※ 결정 트리의 특성 중요도 계산
■ MDI (Mean Decrease in Impurity) Importance
사이킷런에서 트리 계열 모델(DecisionTreeClassifier, DecisionTreeRegressor, RandomForestClassifier, RandomForestRegerssor 등) 은 Mean Decrease in Impurity 방식으로 Importance 를 측정하도록 구현되어 있다.
MDI는 분류 문제에서 '어떤 특성을 사용한 노드가 평균적으로 불순도를 얼마나 감소시키는 지' 를 측정한다.
각 노드에서 사용된 특성에 대해, (현재 노드의 샘플 비율 X 불순도) - (왼쪽 자식 노드의 샘플 비율 X 불순도) - (오른쪽 자식 노드의 샘플 비율 X 불순도) 와 같이 계산하여 더하고, 특성 중요도의 합이 1이 되도록 전체 합으로 나누어 정규화한다.
여기서 샘플 비율은 전체 샘플 수에 대한 비율이다.
회귀 문제에서 '어떤 특성을 사용한 노드가 평균적으로 분산을 어마나 감소시키는 지'를 측정한다.
각 노드에서 사용된 특성에 대해, (현재 노드의 MSE) - (왼쪽 자식 노드의 MSE) - (오른쪽 자식 노드의 MSE) 와 같이 계산하여 더하고, 특성 중요도의 합이 1이 되도록 전체 합으로 나누어 정규화한다.
그런데 이런 불순도 차이 계산 방식은 특성이 갖는 값이 다양할 수록(연속형 변수나 여러 개의 클래스를 갖는 범주형 변수) 특성의 중요도가 크다고 계산하는 경향이 있어, 중요도가 잘못 산정될 수 있다.
예를 들어 응답 변수와 상관없는 random한 값을 갖는 연속형 변수 추가했는데, 해당 컬럼의 중요도가 높게 나온다는 등
뿐만 아니라, 이 방식은 학습 데이터 기반의 지표라 테스트 세트로 일반화된 예측을 하는 데 얼마나 유용한 기능을 하는 지 반영하지 않는다. 심지어, 모델이 과대 적합된 경우 학습할 때 보지 못한 데이터에 대해 제대로 예측 못하는 특성에 높은 중요도를 부여할 수도 있다. 결국 학습 데이터 기반의 지표는 oob를 사용한 지표보다 신뢰성이 떨어진다.
cf. 참고 - Permutation Importance VS MDI Importance
■ Permutation Importance
Permutation Importance는'해당 변수가 랜덤으로 분포한다면 어느 정도 성능이 떨어지는 지' 를 측정한다.
이 방식은 훈련 데이터를 활용하여 측정할 수도 있고 oob 를 활용하여 측정할 수도 있다.
훈련 데이터를 사용하더라도 중요도를 측정하려는 특성의 값을 무작위로 주입하여 계산하므로 새로운 데이터에 대해 제대로 예측하지 못하는 특성에 높은 중요도를 부여할 일이 없다.
1) train data로 모델을 학습시킨다.
2) tarin data/oob data로 생성된 모델의 성능 측정한다.
3) train data/oob data에서 j번째 특성에 대한 값을 무작위로 섞은 후, 모델의 성능을 측정한다.
4) j번째 특성에 대한 특성 중요도는 '2) 측정값' 과 '3) 측정값' 의 차이이다.
5) 여러 예측기의 특성 중요도의 합이 1이 되도록 전체 합으로 나누어 정규화한다.
결국 특정 특성을 무작위로 섞었을 때, 기존 성능보다 낮아진다면 해당 특성 중요도는 높다고 판단한다.
from sklearn.inspection import permutation_importance
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier().fit(X, y)
imp = permutation_importances(rf, X_train, y_train,
oob_classifier_accuracy)
■ Drop Column Importance
'기존 성능에서 특정 특성 빼고 훈련시켰을 때 성능이 얼마나 차이가 나는 가' 를 측정한다.
이를 위해서 특정 특성을 뺀 모델에 대해 재학습시켜야 하는 비용이 따른다.
이 부분이 Permutation Importance 와의 가장 큰 차이점이다.
1) train data로 모델을 학습시킨다.
2) tarin data/oob data 로 생성된 모델의 성능 측정한다.
3) j번째 특성을 제외한 나머지 특성에 대해 train data로 다시 모델을 학습시킨 후 성능을 측정한다.
4) j번째 특성에 대한 특성 중요도는 '2) 측정값' 과 '3) 측정값' 의 차이이다.
5) 여러 예측기의 특성 중요도의 합이 1이 되도록 전체 합으로 나누어 정규화한다.
특정 특성을 빼고 훈련시켰을 때, 기존 성능보다 낮아진다면 해당 특성 중요도는 높다고 판단한다.
해당 방법은 사이킷런에서 라이브러리로 제공하지 않아 직접 코딩으로 구현해야 한다.
def dropcol_importances(rf, X_train, y_train):
rf_ = clone(rf)
rf_.random_state = 999
rf_.fit(X_train, y_train)
baseline = rf_.oob_score_
imp = []
for col in X_train.columns:
X = X_train.drop(col, axis=1)
rf_ = clone(rf)
rf_.random_state = 999
rf_.fit(X, y_train)
o = rf_.oob_score_
imp.append(baseline - o)
imp = np.array(imp)
I = pd.DataFrame(
data={'Feature':X_train.columns,
'Importance':imp})
I = I.set_index('Feature')
I = I.sort_values('Importance', ascending=True)
return I
'Machine Learning > 2. 지도 학습 알고리즘' 카테고리의 다른 글
[모델 알고리즘][앙상블 학습] 그레이디언트 부스팅 (0) | 2021.08.13 |
---|---|
[모델 알고리즘][앙상블 학습] 에이다부스트 (0) | 2021.08.13 |
[모델 알고리즘][앙상블 학습] 배깅, 페이스팅 (0) | 2021.08.13 |
[회귀] 결정 트리 회귀 모델 (0) | 2021.08.13 |
[분류] 결정 트리 분류 모델 (0) | 2021.08.13 |