【机器学习-贷款用户逾期情况分析2】3.stacking模型融合

3.0 任务说明

用你目前评分最高的模型作为基准模型,和其他模型进行stacking融合,得到最终模型及评分果。

 

3.1 stacking模型融合

Stacking(有时候也称之为stacked generalization)是指训练一个模型用于组合(combine)其他各个模型。即首先我们先训练多个不同的模型,然后再以之前训练的各个模型的输出为输入来训练一个模型,以得到一个最终的输出。如果可以选用任意一个组合算法,那么理论上,Stacking可以表示上面提到的各种Ensemble方法。然而,实际中,我们通常使用单层logistic回归作为组合模型。

对于stacking的过程这篇文章我认为讲得比较清楚:

https://blog.csdn.net/qq_32742009/article/details/81366768

我这里再简要说明一下。首先说明一下,stacking可以看成两层结构,第一层结构的输出作为第二层的输入。

我们第一层以svm,lightgbm,xgboost为例,第二层以LR为例作一个讲解,假设训练集有15000个数据,测试集3000个数据,步骤如下:

(1)用svm作五折交叉训练,训练五次,每次将训练集划分为5份,其中一份作为验证集。

(2)每一次将验证集的预测值竖着组合在一起,5次的预测值分别为a1,a2,a3,a4,a5,假设a的大小都是3000*1,将这5个a值再竖着拼在一起,组成A1,A1的大小为15000*1。A1为上图中最后一个橙块。此时A1各个特征对应的标签设为Label_new。

(3)将每一次验证集得到的结果对Test Data作测试,假设每一次测试后产生2000*1的数据,那么五次验证后产生,5个2000*1的数据b1,b2,b3,b4,b5。b1,b2,b3,b4,b5各个位置相加后取平均值得到1个2000*1的数据B1。这个B1为上图中倒数第二个绿块。

(3)同理,将gbm和xgb五折交叉训练后的预测值竖着组成在一起,分别组成A2,A3。将他们对Test Data作预测,得到B2,B3。

(4)将A1,A2,A3横着合并得到一个15000行3列的矩阵A,将B1,B2,B3横着合并得到一个2000行3列的矩阵B。

(5)矩阵A即为新的训练集的特征,矩阵B即为新的测试集的特征。让下一层的模型,基于他们进一步训练。矩阵A的标签是上面步骤2个Label_new,矩阵B的标签即为原来测试集的标签。

我自己写的函数如下:

def Stacking(model,num_folds,x_train,y_train,x_test,y_test):    #输入的模型集合里最后一个模型用作stacking里第二层模型
    y_train=np.array(y_train)
    x_train_folds = []
    y_train_folds = []
    x_train_folds=np.array_split(x_train,num_folds)
    y_train_folds=np.array_split(y_train,num_folds)
    y_pred_A=[]
    y_pred_testseting_A=[]
    label_1=[]
    model_len=len(model)
    for i in range (0,model_len-1):
        y_pred_A.append([])
        y_pred_testseting_A.append([])

    for i in range (num_folds):            #五折交叉验证
        x_train_now=np.zeros((1,x_train.shape[1]))
        y_train_now=np.array([[0]])
        for k in range (5):   #这里的循环是为了将验证集组合在一块儿
            if(k!=i):
                x_train_now=np.vstack((x_train_now,x_train_folds[k]))


                y_train_folds[k]=y_train_folds[k].reshape(y_train_folds[k].shape[0],1)
                y_train_now=np.vstack((y_train_now,y_train_folds[k]))
        x_validation=x_train_folds[i]
        y_validation=y_train_folds[i]
        y_validation=y_validation.reshape((y_validation.shape[0],1))
        x_train_now=np.delete(x_train_now,0,0)   #由于之前vstack之前有1列0,现在需要删除。
        y_train_now=np.delete(y_train_now,0,0)        
        
        for model_nums in range(0,model_len-1):
            model[model_nums].fit(x_train_now,y_train_now)
        label_1.append(y_validation)
        for j in range(0,model_len-1):
            y_pred_A[j].append ( model[j].predict(x_validation))
            y_pred_testseting_A[j].append(model[j].predict(x_test))

            y_pred_A[j][i]=y_pred_A[j][i].reshape((y_pred_A[j][i].shape[0],1))
            y_pred_testseting_A[j][i]=y_pred_testseting_A[j][i].reshape((y_pred_testseting_A[j][i].shape[0],1))

    A=[]   # A里面装博客里写的A1,A2,A3矩阵
    B=[]   #B里面装博客里写的B1,B2..矩阵

    for i in range(0,model_len-1):
        A.append([])
        B.append([])

    for j in range(0,model_len-1):
        y_preds=np.array([[0]])
        for i in range(num_folds):
            y_preds=np.vstack((y_preds,y_pred_A[j][i]))#将5次预测出来的标签组在一起。
        y_preds=np.delete(y_preds,0,0)
        A[j].append(y_preds.copy())
        B1=np.zeros((x_test.shape[0],1))
        for i in range(num_folds):
            B1=B1+y_pred_testseting_A[j][i]
        B[j].append(B1/num_folds)

    x_train_new=np.zeros((A[0][0].shape[0],1))
    x_test_new=np.zeros((B[0][0].shape[0],1))
    label_layer1=np.array([[0]])
    for i in range(0,model_len-1):
        A_now=np.array(A[i]).reshape((A[0][0].shape[0],1))
        B_now=np.array(B[i]).reshape((B[0][0].shape[0],1))
        x_train_new=np.hstack((x_train_new,A_now))
        x_test_new=np.hstack((x_test_new,B_now))
    x_train_new=np.delete(x_train_new,0,1)
    x_test_new=np.delete(x_test_new,0,1)                          #第二层的训练集和测试集特征
 
    for i in range(num_folds):              
        print(label_1[i].shape)
        label_layer1=np.vstack((label_layer1,label_1[i]))         #第二层训练集标签

    label_layer1=np.delete(label_layer1,0,0)
    y_train_new=label_layer1.copy()
    y_test_new=y_test.copy()
    y_test_new=np.array(y_test_new)
    y_test_new=y_test_new.reshape((y_test_new.shape[0]))
    model[model_len-1].fit(x_train_new,y_train_new)
    r,recall,precision,F1,auc=evaluate(model[model_len-1],x_test_new,y_test_new)
    print(r,recall,precision,F1,auc)

我将逻辑回归、lightgbm,rfc,gbdt作为第一层,xgboost作为第二层,代码和结果如下:

Xgb = xgb.XGBClassifier()
gbdt=GradientBoostingClassifier()
gbm = lgb.LGBMClassifier()
rfc = RandomForestClassifier()
Dtree = tree.DecisionTreeClassifier()
svm = SVC(probability=True)
lr = LogisticRegressionCV()
models=[]
models.append(rfc);models.append(gbdt);models.append(gbm);models.append(lr);models.append(Xgb)
Stacking(models,5,x_train,y_train,x_test,y_test)

3.1 stacking接口

自己写完函数才发现,在mlxtend包里有stacking接口,安装直接pip即可:

pip install mlxtend。

StackingClassifier 使用API及参数解析
StackingClassifier(classifiers, meta_classifier, use_probas=False, average_probas=False, verbose=0, use_features_in_secondary=False)
参数:
classifiers : 基分类器,数组形式,[cl1, cl2, cl3]. 每个基分类器的属性被存储在类属性 self.clfs_.
meta_classifier : 目标分类器,即将前面分类器合起来的分类器
use_probas : bool (default: False) ,如果设置为True, 那么目标分类器的输入就是前面分类输出的类别概率值而不是类别标签
average_probas : bool (default: False),用来设置上一个参数当使用概率值输出的时候是否使用平均值。
verbose : int, optional (default=0)。用来控制使用过程中的日志输出,当 verbose = 0时,什么也不输出, verbose = 1,输出回归器的序号和名字。verbose = 2,输出详细的参数信息。verbose > 2, 自动将verbose设置为小于2的,verbose -2.
use_features_in_secondary : bool (default: False). 如果设置为True,那么最终的目标分类器就被基分类器产生的数据和最初的数据集同时训练。如果设置为False,最终的分类器只会使用基分类器产生的数据训练。

属性:
clfs_ : 每个基分类器的属性,list, shape 为 [n_classifiers]。
meta_clf_ : 最终目标分类器的属性

方法:
fit(X, y)
fit_transform(X, y=None, fit_params)
get_params(deep=True),如果是使用sklearn的GridSearch方法,那么返回分类器的各项参数。
predict(X)
predict_proba(X)
score(X, y, sample_weight=None), 对于给定数据集和给定label,返回评价accuracy
set_params(params),设置分类器的参数,params的设置方法和sklearn的格式一样

代码如下:

from mlxtend.classifier import StackingClassifier

sclf = StackingClassifier(classifiers=[rfc, gbdt, gbm,lr], use_probas=True,
                          average_probas=False,
                          meta_classifier=Xgb)
re = sclf.fit(x_train, y_train)
evaluate(re,x_test,y_test)

结果:

将stacking模型和其他模型写一起对比,代码如下(预处理见前两篇文章):

import csv
import os
import numpy as np
import random
import requests
import pandas as pd
import matplotlib.pyplot as plt
import sklearn
from sklearn.linear_model import LogisticRegressionCV,LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn import metrics
from sklearn.svm import SVC
from sklearn import tree
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import GradientBoostingClassifier
import xgboost as xgb
from xgboost import plot_importance
import lightgbm as lgb
from mlxtend.classifier import StackingClassifier


def evaluate(re,x_test,y_test):    #单个模型评估
    r = re.score(x_test,y_test)
    y_pred = re.predict(x_test)    #测试数据预测值
    cmat=metrics.confusion_matrix(y_test, y_pred)  #混淆矩阵
    y_scores=re.predict_proba(x_test) #预测出来的得分,有两列,第一列为此值为0的概率,第二列为此值为1的概率
    y_scores=y_scores[:,1]  #我们这里只需要预测为1的概率
    recall=metrics.recall_score(y_test, y_pred)   #查全率
    precision=metrics.precision_score(y_test,y_pred)  #查准率
    F1=metrics.f1_score(y_test,y_pred)
    auc=metrics.roc_auc_score(y_test, y_scores)  #auc值
    return r,recall,precision,F1,auc

def evaluateAll(models,x_test,y_test):   #所有模型评估
    length=len(models) #模型个数
    r=np.zeros((length));recall=np.zeros((length));precision=np.zeros((length));F1=np.zeros((length));auc=np.zeros((length))
    evaluates=np.zeros((length,5))   #装所有的指标
    for i in range(length):
        r[i],recall[i],precision[i],F1[i],auc[i]=evaluate(models[i],x_test,y_test)
        evaluates[i][0]=r[i];evaluates[i][1]=recall[i];evaluates[i][2]=precision[i];evaluates[i][3]=F1[i];evaluates[i][4]=auc[i];
    return r,recall,precision,F1,auc,evaluates

def drawROC(re,x_test,y_test,title):   #单个模型画ROC
    y_scores=re.predict_proba(x_test) #预测出来的得分,有两列,第一列为此值为0的概率,第二列为此值为1的概率
    y_scores=y_scores[:,1]  #我们这里只需要预测为1的概率
    fpr, tpr, thresholds=metrics.roc_curve(y_test,y_scores,pos_label=None,sample_weight=None,drop_intermediate=True)
    auc=metrics.auc(fpr,tpr)
    plt.plot(fpr,tpr,marker = 'o',label='AUC:{a:0.2f}'.format(a=auc))
    plt.legend(loc="lower right")
    plt.xlabel('False Positive Rate')
    plt.ylabel('True Positive Rate')
    plt.title(title)
    plt.show()
    
def drawAllROC(models,models_name,x_test,y_test,title):   #画所有的ROC曲线
    nums=len(models) #模型个数
    y_scores0=[]    
    y_scores=[]
    for i in range(nums):
        y_scores0.append(models[i].predict_proba(x_test)) #预测出来的得分,有两列,第一列为此值为0的概率,第二列为此值为1的概率   
        y_scores.append(y_scores0[i][:,1])  #我们这里只需要预测为1的概率
    fpr0, tpr0, thresholds0=metrics.roc_curve(y_test,y_scores[0],pos_label=None,sample_weight=None,drop_intermediate=True)
    fpr=[]
    tpr=[]
    thresholds=[]
    auc=[]
    plt.figure()
    plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
    for i in range(nums):
        fpr.append((metrics.roc_curve(y_test,y_scores[i],pos_label=None,sample_weight=None,drop_intermediate=True))[0])
        tpr.append((metrics.roc_curve(y_test,y_scores[i],pos_label=None,sample_weight=None,drop_intermediate=True))[1])
        thresholds.append((metrics.roc_curve(y_test,y_scores[i],pos_label=None,sample_weight=None,drop_intermediate=True))[2])

        auc.append(metrics.auc(fpr[i],tpr[i]))
        plt.plot(fpr[i],tpr[i],label='{0} (AUC:{1:0.2f})'.format(models_name[i], auc[i]))
        plt.legend(loc="lower right")
    plt.xlabel('False Positive Rate')
    plt.ylabel('True Positive Rate')
    plt.title(title)

    plt.show()
#-------------------------------------划分数据----------------------------------------#


x_train, x_test,y_train,y_test= train_test_split(X, y, test_size=0.3,random_state=2018)   #数据集三七分,随机种子2018
#-------------------------------------数据标准化----------------------------------------#
ss = StandardScaler()  
x_train = ss.fit_transform(x_train) #数据标准化
x_test = ss.fit_transform(x_test) #数据标准化

#-------------------------------------logstic----------------------------------------#
lr = LogisticRegressionCV()
lr.fit(x_train,y_train)
#-------------------------------------svm-----------------------------------------#
svm = SVC(probability=True)
svm.fit(x_train,y_train)
#-------------------------------------tree-----------------------------------------#

Dtree = tree.DecisionTreeClassifier()


Dtree.fit(x_train, y_train)
#-------------------------------------随机森林-----------------------------------------#

rfc = RandomForestClassifier()
rfc.fit(x_train, y_train)

#-------------------------------------gbdt-----------------------------------------#
gbdt=GradientBoostingClassifier()
gbdt.fit(x_train, y_train)

#-------------------------------------XGBoost-----------------------------------------#

Xgb = xgb.XGBClassifier()
Xgb.fit(x_train, y_train)
#-------------------------------------lightgbm-----------------------------------------#
gbm = lgb.LGBMClassifier()
gbm.fit(x_train, y_train)

#-------------------------------------Stacking-----------------------------------------#

sclf = StackingClassifier(classifiers=[rfc, gbdt, gbm,lr], use_probas=True,
                          average_probas=False,
                          meta_classifier=Xgb)
sclf.fit(x_train, y_train)

#---------------------------模型评估-----------------------------#
models=[]
models.append(lr);models.append(svm);models.append(Dtree);models.append(rfc);models.append(gbdt);models.append(Xgb);models.append(gbm);models.append(sclf)
models_name=['LR','SVM','TREE','RFC','GBDT','XGBoost','LightGBM','sclf']

r,recall,precision,F1,auc,evaluates=evaluateAll(models,x_test,y_test)
for i in range(len(models)):
    print(models_name[i],evaluates[i])
drawAllROC(models,models_name,x_test,y_test,"all")

结果:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值