[ML수업] 7주차 실습1: Ensemble Learning (Similarity between models, Voting ensemble, Averaging predictions, stacking)
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pylab as plt
%matplotlib inline
import warnings
warnings.filterwarnings("ignore")
# Read Data
from sklearn.datasets import load_breast_cancer
cancer = load_breast_cancer()
cancer_features = pd.DataFrame(data=cancer.data, columns=cancer.feature_names)
#cancer_features
'''
***유방암 진단 데이터***
- 타겟 데이터: 종양이 악성(malignant, 0) or 양성(benign, 1)
- 속성 데이터: 유방암 진단 사진으로부터 측정한 종양(tumar)의 특징값(30 개)
'''
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(cancer_features, cancer.target, random_state=0)
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.neural_network import MLPClassifier
from sklearn.svm import SVC
from sklearn.model_selection import cross_val_score
from sklearn.metrics import accuracy_score
from sklearn.metrics import roc_auc_score
from sklearn.metrics import auc
clfs = []
LR=LogisticRegression(random_state=0); clfs.append(LR)
DT=DecisionTreeClassifier(random_state=0); clfs.append(DT)
MLP=MLPClassifier(random_state=0); clfs.append(MLP)
KNN=KNeighborsClassifier(); clfs.append(KNN)
SVM=SVC(probability=True, random_state=0); clfs.append(SVM)
pred_results = [] #리스트에 값이 다 저장됨.
# 모델별로 성능이 나옴
for clf in clfs :
pred = clf.fit(X_train, y_train).predict_proba(X_test)[:,1]
name = type(clf).__name__
score = roc_auc_score(y_test, pred)
pred_results.append(pd.Series(pred, name=f'{name} \n({score:.4f})'))
print("{:30s} {}".format(name, score))
ensemble_results = pd.concat(pred_results, axis=1)
plt.figure(figsize = (8,6))
g = sns.heatmap(ensemble_results.corr(),annot=True, cmap='Blues')
g.set_title("Correlation between models")
plt.show()
LogisticRegression 0.9930817610062893
DecisionTreeClassifier 0.8939203354297695
MLPClassifier 0.9681341719077569
KNeighborsClassifier 0.9607966457023062
SVC 0.9842767295597485
corr = (ensemble_results.corr().sum()-1)/(ensemble_results.corr().shape[0]-1) #상관관계를 보는 코드
names = corr.index.str[:-10]
aucs = np.array(corr.index.str[-7:-1]).astype(float)
df = pd.DataFrame({'model': names, 'auc': aucs, 'cor': corr})
plt.figure(figsize=(8,6))
g = sns.scatterplot(x="cor", y="auc", data=df, s=40, color='red')
for line in range(0, df.shape[0]):
g.text(df.cor[line]+0.003, df.auc[line]-0.001,
df.model[line], horizontalalignment='left',
size='medium', color='black', weight='semibold')
plt.xlim((df.cor.min()-0.01,df.cor.max()+0.01))
plt.ylim((df.auc.min()-0.01,df.auc.max()+0.01))
plt.xlabel('Mean Agreement')
plt.ylabel('ROC-AUC')
plt.grid()
plt.show()
이걸 통해서 ??모델 별 성능? 유사성? 을 알 수 있다.
그 다음에 해야 할 거:
첫번째로 성능이 가장 좋은 로지스틱~ 를 고르고
두번째로 로지스틱이랑 제일 이질적인 것 중에서 성능이 양호한 걸 골라라 예를들어 SVC
from sklearn.ensemble import VotingClassifier
# 위에서 평가한 모든 모델을 앙상블하는 경우
# 여러 모델을 앙상블하기 위해 VotingClassifier를 생성합니다.
# estimators 매개변수에는 [('모델 이름', 모델 객체), ...] 형식으로 모델과 모델 이름을 지정합니다.
# 매개변수 중 하드는 ???, 소프트는 평균낸다는 뜻
voting = VotingClassifier(
# estimators = [('logit', LR), ('Decision Tree',DT)], voting='hard')
estimators = [(type(clf).__name__, clf) for clf in clfs], voting='hard')
voting.fit(X_train, y_train).score(X_test, y_test)
#0.951048951048951
# 가장 성능이 낮은 DT를 제외하고 앙상블할 경우
voting = VotingClassifier(
estimators = [('lr', LR), ('mlp', MLP), ('knn', KNN), ('svm', SVM)], voting='hard')
voting.fit(X_train, y_train).score(X_test, y_test)
??? 이게 무슨 코드인지는 모르겠음.
from sklearn.ensemble import VotingClassifier
voting = VotingClassifier(
estimators = [('lr', LR), ('mlp', MLP), ('dt', DT)], voting='hard')
voting.fit(X_train, y_train).score(X_test, y_test)
from itertools import product
X = X_train.values[:, [0, 1]]
y = y_train
LR.fit(X, y)
MLP.fit(X, y)
DT.fit(X, y)
voting.fit(X, y)
# Plotting decision regions
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),
np.arange(y_min, y_max, 0.1))
f, axarr = plt.subplots(2, 2, sharex='col', sharey='row', figsize=(10, 8))
for idx, clf, tt in zip(product([0, 1], [0, 1]),
[LR, MLP, DT, voting],
['Logistic Regression', 'Neural Networks', 'Decision Tree', 'Hard Voting']):
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
axarr[idx[0], idx[1]].contourf(xx, yy, Z, alpha=0.4)
axarr[idx[0], idx[1]].scatter(X[:, 0], X[:, 1], c=y, s=20, edgecolor='k')
axarr[idx[0], idx[1]].set_title(tt)
plt.show()
#로지스틱은 직선, 뉴럴은 곡선, 디시전트리는 지지직하면서 과적합이 심함
#짜란 보팅을 하니까 뭐 괜찮아짐
averaging = VotingClassifier(
estimators = [('lr', LR), ('mlp', MLP), ('dt', DT)], voting='soft')
averaging.fit(X_train, y_train)
print('AUC =', roc_auc_score(y_test, averaging.predict_proba(X_test)[:,1]))
#AUC = 0.9909853249475892
from scipy.stats.mstats import gmean
pred_lr = LR.fit(X_train, y_train).predict_proba(X_test)[:,1]
pred_mlp = MLP.fit(X_train, y_train).predict_proba(X_test)[:,1]
pred_dt = DT.fit(X_train, y_train).predict_proba(X_test)[:,1]
print('AUC = ', roc_auc_score(y_test, gmean([pred_lr, pred_mlp, pred_dt], axis=0)))
(코드 없음)
from tqdm import tqdm, tqdm_notebook
from itertools import combinations
# 이 코드에서 가중평균은 빠져있다.
max_score = 0
for p in tqdm_notebook([0, 1, 2.56]): # p==1:산술평균, p=0:기하평균, 그 외:멱평균(주의:멱평균은 과적합 가능성이 높음)
for i in range(2, len(clfs)+1):
for models in combinations(clfs, i):
if p == 0:
pred_mean = gmean([clf.fit(X_train, y_train).predict_proba(X_test)[:,1] for clf in models], axis=0)
else:
preds = [clf.fit(X_train, y_train).predict_proba(X_test)[:,1] for clf in models]
pred_mean = (np.sum(np.array(preds)**p, axis=0) / len(models))**(1/p)
score = roc_auc_score(y_test, pred_mean)
if max_score < score:
best_avg_ensemble = (p, models, score)
max_score = score
# 최적의 앙상블 파라미터(p), 모델 조합, 그리고 AUC 점수를 출력합니다.
p, models, score = best_avg_ensemble
print('p = {}\nmodels = {}\nauc = {}'.format(p, '●'.join([type(clf).__name__ for clf in models]), score))
'''
p = 0
models = LogisticRegression●SVC
auc = 0.9930817610062894
'''
이 코드는 다양한 가중평균 파라미터(p)와 모델 조합을 시도하여 최고의 AUC 점수를 찾습니다. 루프를 사용하여 모델을 훈련하고 예측을 수행하며, 가중평균을 계산합니다. 최적의 앙상블 파라미터(p), 모델 조합, 그리고 AUC 점...
# stacking 함수를 사용하여 모델 스태킹을 수행합니다.
# - models: 모델 리스트
# - X_train, y_train: 훈련 데이터와 레이블
# - X_test: 테스트 데이터
# - regression: 회귀 모델인 경우 True, 분류 모델인 경우 False
# - needs_proba: 확률 예측이 필요한 경우 True, 클래스 레이블 예측이 필요한 경우 False
# - n_folds: 교차 검증의 폴드 수
# - stratified: 분류 작업의 경우 클래스 레이블에 대한 계층화 샘플링을 사용할지 여부
# - shuffle: 데이터를 섞을지 여부
# - random_state: 재현성을 보장하기 위한 난수 시드 값
# - verbose: 실행 정보 출력 (0: 출력 안 함, 1: 요약 정보 출력, 2: 자세한 정보 출력)
from vecstack import stacking
models = clfs
S_train, S_test = stacking(models, # list of models
X_train, y_train, X_test, # data
regression=False, # classification task (if you need
# regression - set to True)
needs_proba=True, # predict class labels (if you need
# probabilities - set to True)
n_folds=5, # number of folds
stratified=True, # stratified split for folds
shuffle=True, # shuffle the data
random_state=0, # ensure reproducibility
verbose=2) # print all info
'''
task: [classification]
n_classes: [2]
metric: [log_loss]
mode: [oof_pred_bag]
n_models: [5]
model 0: [LogisticRegression]
fold 0: [0.17301165]
fold 1: [0.14248485]
fold 2: [0.11332626]
fold 3: [0.05356999]
fold 4: [0.19577129]
----
MEAN: [0.13563281] + [0.04958357]
FULL: [0.13572055]
model 1: [DecisionTreeClassifier]
fold 0: [2.51467349]
fold 1: [3.39234385]
fold 2: [2.12021491]
fold 3: [2.96830087]
fold 4: [2.96830087]
----
MEAN: [2.79276680] + [0.43606857]
FULL: [2.79211399]
...
----
MEAN: [0.21282349] + [0.04062646]
FULL: [0.21290883]
'''
아래는 S_train을 사용하여 메타 모델을 훈련하고, 이 메타 모델을 통해 S_test 데이터에 대한 예측을 수행한 후 ROC AUC 점수를 계산하는 코드 예제입니다. ROC AUC 점수는 이 모델의 성능을 나타내며, 출력으로 표시됩니다.
(ROC AUC(Receiver Operating Characteristic Area Under the Curve) 점수는 이진 분류 모델의 성능을 측정하는 지표 중 하나입니다. ROC 곡선(Receiver Operating Characteristic Curve) 아래의 면적을 나타내며 이 면적이 클수록 모델의 성능이 더 우수하다고 판단됩니다. )
X_train.shape, S_train.shape, X_test.shape, S_test.shape
#((426, 30), (426, 10), (143, 30), (143, 10))
meta_model = LR.fit(S_train, y_train)
roc_auc_score(y_test, meta_model.predict_proba(S_test)[:,1])
#0.9955974842767296
# level-1: LR, DT, MLP, KNN, SVM
models = clfs
S_train, S_test = stacking(models, # list of models
X_train, y_train, X_test, # data
regression=False, # classification task (if you need
# regression - set to True)
needs_proba=True, # predict class labels (if you need
# probabilities - set to True)
metric=accuracy_score, # metric: callable
n_folds=3, # number of folds
stratified=True, # stratified split for folds
shuffle=True, # shuffle the data
random_state=0, # ensure reproducibility
verbose=0) # print all info
# level-2: LR, MLP, DT
# Level-3: Voting
averaging = VotingClassifier(estimators = [('lr', LR), ('mlp', MLP), ('dt', DT)], voting='soft')
averaging.fit(S_train, y_train)
roc_auc_score(y_test, averaging.predict_proba(S_test)[:,1])
# 0.9935010482180294
from sklearn.ensemble import StackingClassifier
# 2-layer stacking
estimators = [(type(clf).__name__, clf) for clf in clfs]
stk_clf = StackingClassifier(
estimators=estimators, final_estimator=LR, cv=5)
stk_clf.fit(X_train, y_train)
roc_auc_score(y_test, stk_clf.predict_proba(X_test)[:,1])
#0.9907756813417191
# 3-layer stacking (Level-3: Voting)
layer_one_estimators = [(type(clf).__name__, clf) for clf in clfs]
voting = VotingClassifier(estimators = [('lr', LR), ('mlp', MLP), ('dt', DT)], voting='soft')
stk_clf = StackingClassifier(estimators=layer_one_estimators, final_estimator=voting, cv=5)
stk_clf.fit(X_train, y_train)
roc_auc_score(y_test, stk_clf.predict_proba(X_test)[:,1])
# 0.9926624737945493
# 3-layer stacking (Level-3: LR)
layer_one_estimators = [(type(clf).__name__, clf) for clf in clfs]
layer_two_estimators = [('lr', LR), ('mlp', MLP), ('dt', DT)]
layer_two = StackingClassifier(estimators=layer_two_estimators, final_estimator=LR)
stk_clf = StackingClassifier(estimators=layer_one_estimators, final_estimator=layer_two, cv=5)
stk_clf.fit(X_train, y_train)
roc_auc_score(y_test, stk_clf.predict_proba(X_test)[:,1])
#0.9920335429769392
(참고)
3-레이어 스태킹과 2-레이어 스태킹의 주요 차이점은 스태킹에 참여하는 모델의 수와 계층(layer)의 개수에 있습니다.
2-레이어 스태킹 (2-Layer Stacking):
2-레이어 스태킹은 두 개의 계층(layer)으로 구성됩니다.
첫 번째 계층(layer-1)에서는 여러 다양한 기본 모델(예: 로지스틱 회귀, 의사결정 트리, 랜덤 포레스트 등)이 훈련되고 예측을 수행합니다.
두 번째 계층(layer-2)에서는 첫 번째 계층의 예측 결과를 사용하여 최종 예측을 수행하는 메타 모델(예: 로지스틱 회귀)이 훈련됩니다.
최종 예측은 메타 모델이 계산한 결과입니다.
3-레이어 스태킹 (3-Layer Stacking):
3-레이어 스태킹은 세 개의 계층(layer)으로 구성됩니다.
첫 번째 계층(layer-1)에서는 여러 다양한 기본 모델이 훈련되고 예측을 수행합니다.
두 번째 계층(layer-2)에서는 첫 번째 계층의 예측 결과를 사용하여 중간 예측을 수행하는 중간 모델이 훈련됩니다.
세 번째 계층(layer-3)에서는 중간 모델의 예측 결과를 사용하여 최종 예측을 수행하는 메타 모델이 훈련됩니다.
최종 예측은 메타 모델이 계산한 결과입니다.
주요 차이점은 2-레이어 스태킹에서는 중간 예측을 수행하는 중간 모델이 없고, 메타 모델이 바로 첫 번째 계층의 예측 결과를 사용하여 최종 예측을 수행하는 반면, 3-레이어 스태킹에서는 중간 예측을 수행하는 중간 모델이 추가되어 계산 과정이 더 복잡해집니다. 3-레이어 스태킹은 보다 복잡한 앙상블 구조를 만들어내며, 모델 간의 상호작용을 더 잘 캡처할 수 있을 수 있지만, 계산 비용이 더 많이 들 수 있습니다.