模型融合之Stacking

前言

最近研究模型融合,看到很多关于介绍Stacking的文章,大多数文章都有这张图。如果你能一眼看懂,OK,那你就不用继续读下去了。如果一下子看不懂,我会结合代码具体介绍Stacking是如何工作的。
图一

一、Stacking是什么?

Stacking 是集成学习的一种方法。集成学习可以融合不同模型学习到的特征以提升最终的预测效果。一般来说,集成学习的要求基学习器好而不同。即每个基学习器性能不能太差,同时不同的基学习器学习的特征不同。

二、代码实现

本示例使用Sklearn的威斯康辛州乳腺癌数据集

1.引入库并划分数据集

from sklearn.model_selection import StratifiedKFold,StratifiedShuffleSplit
from sklearn.metrics import roc_auc_score, f1_score,accuracy_score
from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import GradientBoostingClassifier
import lightgbm as lgb
import pandas as pd
import numpy as np
random_ = 2022

data_X, data_y = load_breast_cancer(return_X_y=True, as_frame=True)
SSS = StratifiedShuffleSplit(n_splits=1,random_state=2022,test_size=0.2)
#划分数据集
for train_index, test_index in SSS.split(data_X, data_y):
    train_X, train_y = data_X.iloc[train_index], data_y[train_index]
    test_X, test_y = data_X.iloc[test_index], data_y[test_index]

print(f'train_X shape:{train_X.shape}, train_y shape:{train_y.shape}')
print(f'test_X shape:{test_X.shape},   test_y shape:{test_y.shape}') 
"""
train_X shape:(455, 30), train_y shape:(455,)
test_X shape:(114, 30),   test_y shape:(114,)
"""   

2.定义模型

为了方便理解上图,我将每一个基学习器单独定义为一个模型,本例中只使用了GBDT和RF两个基学习器。

def model_gbdt(train_X, train_y, test_X, test_y, K_fold, random_):
    Skf = StratifiedKFold(n_splits=K_fold,shuffle=True,random_state=random_)
    train_predict = np.zeros(len(train_X))
    test_predict = np.zeros(len(test_y)) 
    for tra_idx, val_idx in Skf.split(train_X,train_y):
        tra_X, tra_y = train_X.iloc[tra_idx], train_y.iloc[tra_idx]
        val_X, val_y = train_X.iloc[val_idx], train_y.iloc[val_idx]
        model = GradientBoostingClassifier(learning_rate=0.1,
                                           max_depth=2,
                                           n_estimators=3)
        model.fit(tra_X, tra_y)
        val_predict = model.predict(val_X)
        train_predict[val_idx] = val_predict
        test_predict += model.predict(test_X)/K_fold
    test_pre = test_predict.copy()
    test_predict[test_predict > 0.5], test_predict[test_predict < 0.5] = 1, 0
    print('model_gbdt auc:',roc_auc_score(test_y, test_pre))
    return train_predict, test_pre, test_predict
    
train_gbdt, test_gbdt, test_gbdt_ = model_gbdt(train_X, train_y,
                                   test_X, test_y, 5, random_)
"""
输入结果:
model_gbdt auc: 0.998015873015873
"""

对于model_gbdt(相当于上图中的model1)其实我们训练了五个模型(这里的模型指的是estimator)。这里有人会想怎么是五个模型,熟悉K折交叉验证的话便很快就明白。
其实model_gbdt是将数据集划分为5份,每一次使用其中四份数据(即上图的蓝色learn部分)学习一个estimator,然后在剩下的一份数据(上图的橙色Predict部分)上验证,重复学习五个estimator。图中的五个model1,其实就是五个在不同数据集下(不同的蓝色learn部分)训练得到的estimator。最后可以得到model_gbdt对所有训练集的预测结果,同时每一个estimator可以预测得到一个测试集的结果(五个estimator即有五个结果,相当于上图中五个连续的绿色Predict),最后将这五个结果求平均则为model_gbdt对测试集最终的预测结果。

def model_rf(train_X, train_y, test_X, test_y,K_fold, random_):
    Skf = StratifiedKFold(n_splits=K_fold,shuffle=True,random_state=random_)
    train_predict = np.zeros(len(train_X))
    test_predict = np.zeros(len(test_y)) 
    for tra_idx, val_idx in Skf.split(train_X,train_y):
        tra_X, tra_y = train_X.iloc[tra_idx], train_y.iloc[tra_idx]
        val_X, val_y = train_X.iloc[val_idx], train_y.iloc[val_idx]
        model = RandomForestClassifier(n_estimators=1,
                                       max_depth=1,
                                       bootstrap=False,
                                       random_state=2)
        model.fit(tra_X, tra_y)
        val_predict = model.predict(val_X)
        train_predict[val_idx] = val_predict
        test_predict += model.predict(test_X)/K_fold
    test_pre = test_predict.copy()
    test_predict[test_predict > 0.5], test_predict[test_predict < 0.5] = 1, 0
    print('model_rf accuracy_score:',roc_auc_score(test_y, test_pre))
    return train_predict, test_pre, test_predict

train_rf, test_rf, test_rf_ = model_rf(train_X, train_y, 
                                       test_X, test_y, 5, random_)
"""
输入结果:
model_rf auc: 0.9836309523809524
"""

model_rf相当于model2,当然也可以有model3,model4…,基于篇幅这里就简单介绍两个基学习器的Stacking。Stacking第二层的模型也可以选择gbdt,lgb,xgb等,但通常基学习器的性能较好,Stacking的时候使用简单的lr就行了。

def stacking(data_train_X, train_y, data_test_X, test_y):
    model = LogisticRegression()
    model.fit(data_train_X, train_y)
    test_stack = model.predict_proba(data_test_X)[:,1]
    auc= roc_auc_score(test_y, test_stack)
    print('Stacking auc:', auc)
    return test_stack
   
stacking_train_X = pd.DataFrame({'gbdt':train_gbdt,'rf':train_rf})
stacking_test_X = pd.DataFrame({'gbdt':test_gbdt,'rf':test_rf})
test_stack = stacking(stacking_train_X, train_y, stacking_test_X, test_y)
"""
输出结果
Stacking auc: 0.9966931216931217
"""

我们发现,相比于gbdt模型的 0.998和rf模型的0.983,Stacking的融合结果为0.996。这表明使用Stacking融合的结果在趋近性能最优的基模型。虽然Stacking融合的效果并没有gbdt模型好,但是这并不是说Stacking没有效果。由于本文数据集较少,单个基模型就能达到接近1的效果,使用Stacking效果并不明显。

造成Stacking效果不明显的原因可能包括:
1.数据集较少
2.基模型性能差
3.基模型数量少等。

Stacking可以有以下的理解:
1.第一层做的是特征变换,第二层做的做结果预测;
2.第一层是各个模型进行预测,第二层进行结果筛选;
3.第一层是模型预测,第二层是置信度的打分和加权平均。

具体的工程实现可以参考下文

https://github.com/kaz-Anova/StackNet#restacking-mode

  • 1
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值