【机器学习】之模型融合技术


本文部分内容摘取自:

https://blog.csdn.net/sinat_35821976/article/details/83622594

https://blog.csdn.net/u014248127/article/details/78993753


模型优化之模型融合简介

在产业化的机器学习建模任务中,耗时最长的是数据处理和模型优化两个方面,今天讲讲模型优化的方法。

 

对于初学者而言,模型优化一般仅仅体现在调参的工作之中,即通过对模型内置的参数或者正则项进行调优使模型表现达到最佳。然而在真正的机器学习任务中,模型调参只是很基本的一部分,一方面在于常用的机器学习方法中,单一模型的复杂度一般不高,基于给定的学习目标单一模型拟合的程度有上限;另一方面在于模型的优化往往在于对bad case的优化,而bad case的出现一般是由于模型本身局限性引起的,优化bad case一般需要重构模型结构或是重构基模型方法。

 

模型融合技术就可以很好的解决这些问题。所谓模型融合,就是先学习一组个体学习器,然后通过特定的手段将他们结合起来,以加强模型效果。其中个体学习器就是我们口头常说的机器学习算法,特定的手段就是模型融合所需学习的特别手段,这也是我们本文的主要内容。

 

模型融合为什么有效果呢?根据研究表明,随着个体学习器数目的增加,集成学习器的错误率将呈指数级下降,最终趋于零。因为个体学习器多样性大,最终准确率高,通俗的讲就是达到了“取长补短”的效果。

 

模型融合方法

模型融合技术主要分为两类:

一种是个体学习器之间不存在强依赖关系的融合方法,典型代表为Bagging

一种是个体学习器之间存在强依赖关系的融合方法,典型代表为Boosting

下面对各大主流模型融合方法进行介绍

 

1. Bagging方法

Bagging方法是从训练集中抽样得到每个基模型所需的子训练集,然后对所有基模型预测的结果进行综合,产生最终的预测结果

Bagging算法:采用的是自助采样法(Bootstap sampling),即对于m个样本的原始训练集,我们每次先随机采集一个样本放入采样集,接着把该样本放回,也就是说下次采样时该样本仍有可能被采集到,这样采集m次,最终可以得到m个样本的采样集,由于是随机采样,这样每次的采样集是和原始训练集不同的,和其他采样集也是不同的,这样得到多个不同的弱学习器。

 

Bagging方法系最典型的代表便是Random Forest算法,该算法主要的是基本学习器限定为决策树,并且除了在样本上加上扰动,同时在属性上也加了扰动进行多学习器的学习。模型通过sklearn可以直接调用,这里就不再细说了。

from sklearn.ensemble import RandomForestClassifier

2. Boosting方法

Boosting算法的工作机制是首先从训练集用初始权重训练出一个弱学习器1,根据弱学习的学习误差率表现来更新训练样本的权重,使得之前弱学习器1学习误差率高的训练样本点的权重变高,使得这些误差率高的点在后面的弱学习器2中得到更多的重视。然后基于调整权重后的训练集来训练弱学习器2;如此重复进行,直到弱学习器数达到事先指定的数目T,最终将这T个弱学习器通过集合策略进行整合,得到最终的强学习器。

 

Boosting算法中最常见的是Adaboost算法以及Boosting Tree系列算法。

Adaboost算法是加法模型、损失函数为指数函数、学习算法为前向分布算法时的二分类算法。

Boosting Tree系列算法是加法模型、学习算法为前向分布算法时的算法。不过它限定基本学习器为决策树。其中最为被广泛应用的是Gradient Boosting Tree,例如大家耳熟能详的GBDT、LightGBM、XGBoost算法都属于这一族。这些算法都可以通过现成的包进行调用。

from sklearn.ensemble import AdaBoostClassifier
from sklearn.ensemble import GradientBoostingClassifier
from lightgbm import LGBMClassifier
from xgboost import XGBClassifier

 

以上均是算法层面的融合办法,对于最终预测结果同样可以采取一定的策略进行融合。接下来介绍预测结果融合策略。

预测结果融合策略

1. Voting

Voting即投票机制,有绝对多数投票(得票超过一半),相对多数投票(得票最多)——硬投票,加权投票——软投票,一般用于分类模型。

 

2. Averaging

即平均法,将模型最终输出结果平均值作为最终预测值,同软投票的思路一样可以通过加权平均得到最终预测值。

 

相比于Voting和Averaging这种简单的加和方法,一下介绍几种“学习法”,即通过另一个学习器来进行结合,把个体学习器称为初级学习器,用于结合的学习器称为次级学习器或元学习器。

3. Stacking

Stacking 先从初始数据集训练出初级学习器,然后”生成”一个新数据集用于训练次级学习器。在这个新数据集中,初级学习器的输出被当作样例输入特征,而初始样本的标记仍被当作样例标记。

stacking一般使用交叉验证的方式,初始训练集D 被随机划分为k 个大小相似的集合D1 , D2 , … , Dk,每次用k-1个部分训练T个模型,对另个一个部分产生T个预测值作为特征,遍历每一折后,也就得到了新的特征集合,标记还是源数据的标记,用新的特征集合训练一个集合模型。

 

Stacking流程比较复杂因为涉及到交叉验证的过程,具体如下:

 

  1. 将数据划分为训练集和测试集(test_set),对训练集进行划分为K个大小相似的集合,取其中一份作为验证集val_set,其余的为训练集train_set;
  2. 创建第一层的多个模型,这些模型可以使同质的也可以是异质的;
  3. 对于每一个模型来说,利用各自的train_set训练各自的模型,训练好的模型对各自的val_set和test_set进行预测,得到val_predict和test_predict;
  4. 创建第二层的模型,将每个模型对应的val_predict拼接起来作为第二层的训练集,将所有模型的test_predict取平均值作为第二层的测试集;用训练好的第二层模型对第二层的测试集进行预测,得到的结果即为整个测试集的结果

(图片来源于网络)

 

4. Blending

Blending与Stacking大致相同,只是Blending的主要区别在于训练集不是通过K-Fold的CV策略来获得预测值从而生成第二阶段模型的特征,而是建立一个Holdout集,例如说10%的训练数据,第二阶段的stacker模型就基于第一阶段模型对这10%训练数据的预测值进行拟合。说白了,就是把Stacking流程中的K-Fold CV 改成 HoldOut CV。Blending相较于Stacking来说要简单一些,其流程大致分为以下几步:

  1. 将数据划分为训练集和测试集(test_set),其中训练集需要再次划分为训练集(train_set)和验证集(val_set);
  2. 创建第一层的多个模型,这些模型可以使同质的也可以是异质的;
  3. 使用train_set训练步骤2中的多个模型,然后用训练好的模型预测val_set和test_set得到val_predict, test_predict1;
  4. 创建第二层的模型,使用val_predict作为训练集训练第二层的模型;
  5. 使用第二层训练好的模型对第二层测试集test_predict1进行预测,该结果为整个测试集的结果

(图片来源于网络)

对于Voting方法和Averaging方法,只用对最终模型的结果进行简单计算即可,这里就不列出代码。以下给出Stacking和Blending过程的方法,方法中以RandomForestClassifier(), GradientBoostingClassifier(), XGBClassifier(), LGBMClassifier()作为基融合模型示例,以RandomForestClassifier作为最终融合模型示例。需要注意的是,一般模型最终融合时,可加入原始特征并入第一层预测输出值作为最终训练数据,这样可以加强模型鲁棒性。

"""
@Time : 2021/1/7 11:24
@Auth : Yifan Hu
@File :stacking.py
@IDE :PyCharm
"""

from sklearn.model_selection import StratifiedKFold
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from xgboost import XGBClassifier
from lightgbm import LGBMClassifier
import pandas as pd
import numpy as np

X_train = pd.DataFrame().values
y_train = pd.Series().values
X_test = pd.DataFrame().values

folds = 4
if_concat_origin_data = True

kf = StratifiedKFold(n_splits=folds, shuffle=True, random_state=2021)

model_list = [RandomForestClassifier(), GradientBoostingClassifier(), XGBClassifier(), LGBMClassifier()]
model_final = RandomForestClassifier()

train_x_final = np.zeros([X_train.shape[0], len(model_list)])
test_x_final = np.zeros([X_test.shape[0], len(model_list)])
for model_index, model in enumerate(model_list):
    train_x = np.zeros([X_train.shape[0], 1])
    test_x = np.zeros([folds, X_test.shape[0]])
    for i, (train_index, val_index) in kf.split(X_train, y_train):
        train = X_train[train_index]
        train_y = y_train[train_index]
        val = X_train[val_index]
        model.fit(train, train_y)
        y_val = model.predict_proba(val)[:, 1]
        y_test = model.predict_proba(X_test)[:, 1]
        train_x[train_index] = y_val.reshape(-1, 1)
        test_x[i, :] = y_test
    train_x_final[:, model_index] = train_x
    test_x_final[:, model_index] = np.mean(test_x, axis=0)

if if_concat_origin_data:
    train_x_final = np.concatenate([X_train, train_x_final], axis=1)
    test_x_final = np.concatenate([X_test, test_x_final], axis=1)

model_final.fit(train_x_final, y_train)
model_final.predict_proba(test_x_final)[:, 1]
"""
@Time : 2021/1/7 13:48
@Auth : Yifan Hu
@File :blending.py
@IDE :PyCharm
"""

from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from xgboost import XGBClassifier
from lightgbm import LGBMClassifier
import pandas as pd
import numpy as np

X_train = pd.DataFrame().values
y_train = pd.Series().values
X_test = pd.DataFrame().values

if_concat_origin_data = True

x_train, x_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.3, random_state=2020, stratify=y_train)

model_list = [RandomForestClassifier(), GradientBoostingClassifier(), XGBClassifier(), LGBMClassifier()]
model_final = RandomForestClassifier()

val_x_final = np.zeros([x_val.shape[0], len(model_list)])
test_x_final = np.zeros([X_test.shape[0], len(model_list)])
for model_index, model in enumerate(model_list):
    model.fit(x_train, y_train)
    y_val = model.predict_proba(x_val)[:, 1]
    y_test = model.predict_proba(X_test)[:, 1]
    val_x_final[:, model_index] = y_val
    test_x_final[:, model_index] = y_test

if if_concat_origin_data:
    val_x_final = np.concatenate([X_train, val_x_final], axis=1)
    test_x_final = np.concatenate([X_test, test_x_final], axis=1)

model_final.fit(val_x_final, y_val)
model_final.predict_proba(test_x_final)[:, 1]

 

模型融合是机器学习算法调优的一个重要技术手段,然而它并不是万能的,因为数据质量决定了机器学习的效果的上限,如果盲目的使用融合而未考虑真实业务需求去进行调优一定是徒劳的。

希望大家有所收获!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值