《机器学习算法竞赛实战》-chapter6模型融合

news2024/11/15 11:17:48

模型融合

模型融合常常是竞赛取得胜利的关键!
具有差异性的模型融合往往能给结果带来很大的提升。虽然并不是每次使用模型融合都能起到很大的作用,但是就平常的竞赛经验而言,尤其是在最终成绩相差不大的情况下,模型融合的方法往往会成为取胜的关键之一。
作者从构建多样性训练过程融合训练结果融合三部分介绍不同模型融合方法的应用场景。

1 构建多样性

1.1 特征多样性

构建多个有差异的特征集并分别建立模型,可使特征存在于不同的超空间,从而建立的多个模型有不同的泛化误差,最终模型融合时可以起到互补的效果。在竞赛中,队友之间的特征集往往是不一样的,在分数差异不大的情况下,直接进行模型融合基本会获得不错的收益。
另外,像随机森林的max_featuresXGBoost中的colsample_bytreeLightGBM中的feature_fraction都是用来对训练集中的特征进行采样的,其实本质上就是构建特征的多样性。

1.2 样本多样性

样本多样性来自于不同的样本集,具体的做法是将数据集切分成多份,然后分别建立模型。我们知道很多树模型在训练时会进行采样,主要目的是防止过拟合,从而提升预测的准确性。
有时候将数据集切分为多份并不是随机进行的,而是根据具体的赛题数据进行切分,需要考虑如何切分可以构建最大限度的数据差异性,并用切分后的数据分别训练模型(2019年天池“全球城市计算AI挑战赛”)。

1.3 模型多样性

不同模型对数据的表达能力是不同的,比如FM(Factorization Machine,因子分解机)能够学习到特征之间的交叉信息,并且记忆性较强;树模型可以很好的处理连续特征和离散特征(比如LightGBM和CatBoost),并且对异常值也具有很好的健壮性。把这两类在数据假设、表征能力方面有差异的模型融合起来肯定会达到一定的效果。

还有很多其他构建多样性的方法,比如训练目标多样性、参数多样性和损失函数选择的多样性等,都能产生非常好的效果。

2 训练过程融合

模型融合的方式有两种,第一种是训练过程融合,例如随机森林和XGBoost,这两种模型在训练种构造多个决策树进行融合,多个决策树可以看成是多个弱分类器,随机森林通过Bagging的方式进行融合,XGboost通过Boosting的方式进行融合。

2.1 Bagging

Bagging从训练集中有放回的取出数据,这些数据构成样本集,这也保证了训练集的规模不变,然后用样本集训练弱分类器。重复上述过程多次,取平均值或者采用投票机制获取模型融合的最终结果。
Bagging通过减小误差之间的差来减少分类器的方差。换言之Bagging可以降低过拟合的风险。Bagging算法的效率来自于训练数据的不同,各模型之间存在很大的差异,并且在加权融合的过程中可使训练数据的错误相互抵消。
可以选择相同的分类器进行训练,也可以选择不同的分类器。

2.2 Boosting

Boosting的思想其实并不难理解,首先训练一个弱分类器,并把这个弱分类器分错类的样本记录下来,同时给予这个弱分类器一定的权重;然后建立一个新的弱分类器给予前面的错误样本进行训练,同样,我们也给予这个分类器一个权重。重复上面的过程,直到弱分类器的性能达到某一指标,例如当建立的新弱分类器并不会使准确度显著提升的时候停止迭代。最后将这些弱分类器各自乘上相应的权重并全部加起来,得到最后的强分类器。
基于Boosting的算法AdaBoostLightGBMXGBoostCatBoost

3 训练结果融合

模型融合的第二种方式是训练结果融合,主要分为加权法、StackingBlending,这些方法都可以有效的提高模型的整体预测能力。

3.1 加权法

加权法对于一系列任务(比如分类和回归)和评价指标(如AUC、MSE或Logloss)都是很有效的,比如我们有10个算法模型都预测到了结果,直接对这10个结果取平均值或者给予每个算法不同的权重,即得到了融合结果。加权法通常还能减少过拟合,因为每个模型的结果可能存在一定的噪声。
对于分类问题,可以使用的方法有投票法加权法等。
对于回归问题,可以使用的加权法有算术平均几何平均等,当评分规则是SMAPE(平均绝对百分比误差)时,选择算数平均会使模型融合的结果偏大,这不符合SMAPE的直觉,越小的值对评分影响越大,所以选择几何平均,能够使结果偏向小值。
对于排序问题如果是使用MRR作为评价指标,命名的位置越靠前,得分也越高。因此我们不仅进行加权融合,还需要让结果偏向小值,这时候就要对结果进行转换,然后再用加权法进行融合,一般而言使用的转换方式是log变换,如果以AUC作为排序指标,一般使用排序均值的融合思路。

3.2 Stacking融合

使用加权法进行融合虽然简单,但需要人工来确定权重,因此可以考虑更加智能的方式,通过新的模型来学习每个分类器的权重。我们假设有两层分类器,如果在第一层中某个特定的基分类器错误的学习了特征空间的某个区域,这种错误的学习行为可能会被第二层分类器检测到,这与其他分类器的学习行为一样,可以纠正不恰当的训练。上述过程就是Stacking融合的基本思想。
这里注意两点:第一,构建的新模型一般是简单模型,比如逻辑回归这样的线性模型;第二,使用多个模型进行Stacking融合会有比较好的效果。
Stacking融合使用基模型的预测结果作为第二层模型的输入,我们不能简单地使用完整的训练集数据来训练基模型,这会产生基分类器在预测时就已经看到测试集的风险,因此在提供预测结果时出现过拟合问题。所以我们使用Out-of-Fold的方式进行预测,也就是使用K折交叉验证的方式来预测结果。

4 实战案例

完成Stacking融合的操作需要构造多个模型的预测结果,一般是三个以上,这里选择ExtraTreesRegressorRandomForestRegressorRidgeLasso作为基分类器,Ridge作为最终分类器。

from sklearn.ensemble import ExtraTreesRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error
from sklearn.linear_model import Ridge, Lasso
from math import sqrt
from sklearn.model_selection import KFold
import pandas as pd
# 五折交叉验证
kf = KFold(n_splits=5, shuffle=True, random_state=2023)
train = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')

all_data = pd.concat((train,test))
all_data = pd.get_dummies(all_data)
# 填充缺失值
all_data = all_data.fillna(all_data.mean())
# 数据切分
x_train = all_data[:train.shape[0]]
x_test = all_data[train.shape[0]:]
y_train = train.SalePrice

构建一个针对sklearn中模型的功能类,初始化参数然后训练和预测。

class SklearnWrapper(object):
    def __init__(self, clf, seed=0, params=None):
        params['random_state'] = seed
        self.clf = clf(**params)
    
    def train(self, x_train, y_train):
        self.clf.fit(x_train, y_train)
    
    def predict(self, x):
        return self.clf.predict(x)

封装交叉验证函数,这段代码的可复用性强。

import numpy as np
def get_oof(clf):
    oof_train = np.zeros((x_train.shape[0], ))
    oof_test = np.zeros((x_test.shape[0], ))
    oof_test_skf = np.empty((5, x_test.shape[0]))

    scores = []

    for i, (train_index, valid_index) in enumerate(kf.split(x_train, y_train)):
        trn_x, trn_y, val_x, val_y = x_train.iloc[train_index], y_train[train_index], \
            x_train.iloc[valid_index], y_train[valid_index]
        clf.train(trn_x, trn_y)
        oof_train[valid_index] = clf.predict(val_x)
        oof_test_skf[i, :] = clf.predict(x_test)

        score_single = sqrt(mean_squared_error(val_y, oof_train[valid_index]))
        scores.append(score_single)
        
    print(f'mean: {np.mean(scores)}')

    oof_test[:] = oof_test_skf.mean(axis=0)
    return oof_train.reshape(-1, 1), oof_test.reshape(-1, 1)

接下来是基分类器训练和预测的部分代码,可预测四个模型的验证集结果和测试集结果,并辅助最后一步的Stacking融合。

et_params = {
    'n_estimators': 100,
    'max_features': 0.5,
    'max_depth': 12,
    'min_samples_leaf':2
}

rf_params = {
    'n_estimators': 100,
    'max_features': 0.2,
    'max_depth': 12,
    'min_samples_leaf': 2
}

rd_params = {'alpha': 10}
ls_params = {'alpha': 0.005}

et = SklearnWrapper(clf=ExtraTreesRegressor, seed=2023, params=et_params)
rf = SklearnWrapper(clf=RandomForestRegressor, seed=2023, params=rf_params)
rd = SklearnWrapper(clf=Ridge, seed=2020, params=rd_params)
ls = SklearnWrapper(clf=Lasso, seed=2020, params=ls_params)

print('使用极限树:')
et_oof_train, et_oof_test = get_oof(et)
print('使用随机森林:')
rf_oof_train, rf_oof_test = get_oof(rf)
print('使用岭回归:')
rd_oof_train, rd_oof_test = get_oof(rd)
print('使用Lasso回归:')
ls_oof_train, ls_oof_test = get_oof(ls)

在这里插入图片描述
最后是Stacking部分,使用Ridge模型,当然也可以尝试树模型这类更加复杂的模型。

def stack_model(oof_1, oof_2, oof_3, oof_4, predictions_1, predictions_2, predictions_3, predictions_4, y):
    train_stack = np.hstack([oof_1, oof_2, oof_3, oof_4])
    test_stack = np.hstack([predictions_1, predictions_2, predictions_3, predictions_4])

    oof = np.zeros((train_stack.shape[0]))
    predictions = np.zeros((test_stack.shape[0]))
    scores = []

    for fold_, (trn_idx, val_idx) in enumerate(kf.split(train_stack, y)):
        trn_data, trn_y = train_stack[trn_idx], y[trn_idx]
        val_data, val_y = train_stack[val_idx], y[val_idx]

        clf = Ridge(random_state=2020)
        clf.fit(trn_data, trn_y)
         
        oof[val_idx] = clf.predict(val_data)
        predictions += clf.predict(test_stack) / 5

        score_single = sqrt(mean_squared_error(val_y, oof[val_idx]))
        scores.append(score_single)
        print(f'{fold_ + 1} / {5}', score_single)
    print(f'mean: {np.mean(scores)}')
    
    return oof, predictions

Stacking融合

print('使用Stack:')
oof_stack, predictions_stack = stack_model(et_oof_train, rf_oof_train, rd_oof_train, ls_oof_train, et_oof_test, rf_oof_test, rd_oof_test, ls_oof_test, y_train)

在这里插入图片描述
github笔记本地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/498451.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

法规标准-GB/T 39265标准解读(2020版)

GB/T 39265是做什么的? GB/T 39265全名为道路车辆 盲区检测系统性能要求及试验方法,其中主要是对BSD系统的性能要求及测试步骤进行了介绍。本文仅解读M1、N1类车辆相关内容。 一般要求 系统开启与关闭 1.BSD系统应具备手动开启和关闭的功能 2.手动关…

巧用 exports 和 typeVersions 提升 npm 包用户使用体验

默认导出 对于开发一个 JavaScript 三方库供外部使用而言,package.json是其中不可缺少的一部分 一般而言,对于库开发者来说,我们会在package.json中指定我们的导出入口。一般而言会涉及两个字段main和export,它们会涉及到当前模…

开关电源基础03:正激和反激开关电源拓扑(2)-半桥和全桥拓扑

说在开头:关于薛定谔的波动方程(3) 波动方程在矩阵派的内部也大受欢迎,首先是海森堡的老师索末菲,然后是建立矩阵力学的核心人物之一的另一位老师:马克思.玻恩。玻恩在薛定谔方程刚出来时就赞扬了他的成就…

宕机了?!DolphinScheduler 高可用和 Failover 机制关键时刻保命

点击蓝字 关注我们 高可用性是 Apache DolphinScheduler 的特性之一。它通过冗余来避免单点问题,所有组件天然支持横向扩容;但仅仅保证了冗余还不够,当系统中有节点宕机时,还需要有故障转移机制能够自动将宕机节点正在处理的工作转…

【react 全家桶】高级指引(上)

本人大二学生一枚&#xff0c;热爱前端&#xff0c;欢迎来交流学习哦&#xff0c;一起来学习吧。 <专栏推荐> &#x1f525;&#xff1a;js专栏 &#x1f525;&#xff1a;vue专栏 &#x1f525;&#xff1a;react专栏 文章目录 12 【react高级指引&#xff08;上&…

I.MX6Q-SDB开发板移植ubuntu

I.MX6Q-SDB开发板移植ubuntu 0.前言一、准备工作二、ubuntu移植1.下载ubuntu发布的根文件系统2.根文件系统的简单修改3.板卡适配设置4.打包根文件系统 三、烧写镜像1.dd命令2.uuu工具3.mfgtool工具4.i.mx6q-sdb的拨码设置&#xff1a; 四、大无语事件 0.前言 这两天收拾杂货堆&…

密码学【java】初探究加密方式之数字签名

文章目录 前言1 数字签名简介2 基本原理3 数字证书4 网页加密5 edge的网站连接图标6 代码实现7 keytool工具使用7.1 常用命令&#xff1a;7.2 生成私钥公钥[未实践成功]7.3 导出公钥 前言 有关keytool的使用部分&#xff0c;未实现&#xff0c;先记录下来&#xff01;&#xf…

『python爬虫』12. 模拟登陆之cookie的使用(保姆级图文)

目录 session1. 模拟登陆取得cookie2. 在登录的情况下继续取得书架上的数据3. 在已经有cookie的情况下直接请求总结 欢迎关注 『python爬虫』 专栏&#xff0c;持续更新中 欢迎关注 『python爬虫』 专栏&#xff0c;持续更新中 session session和我们之前用的request十分相似&…

AWS Lambda - 同步/异步调用,事件源,目标

Hello大家好&#xff0c;我们今天继续讨论AWS Lambda的内容。 同步调用 Lambda函数有三种调用方式。 第一种方式是同步调用。 当我们使用API、CLI以及API网关等调用函数时&#xff0c;就是同步调用。 当您同步调用函数时&#xff0c;Lambda会运行该函数并等待响应&#xff…

微服务---Redis入门篇-Redis的常见命令和客户端使用

Redis快速入门 Redis的常见命令和客户端使用 1.初识Redis Redis是一种键值型的NoSql数据库&#xff0c;这里有两个关键字&#xff1a; 键值型 NoSql 其中键值型&#xff0c;是指Redis中存储的数据都是以key、value对的形式存储&#xff0c;而value的形式多种多样&#xf…

易视腾iS-E5-NGH_3798MV100_MT7601_卡刷固件包_当贝纯净桌面

易视腾iS-E5-NGH_3798MV100_MT7601_卡刷固件包_当贝纯净桌面 特点&#xff1a; 1、适用于对应型号的电视盒子刷机&#xff1b; 2、开放原厂固件屏蔽的市场安装和u盘安装apk&#xff1b; 3、修改dns&#xff0c;三网通用&#xff1b; 4、大量精简内置的没用的软件&#xff0…

单链表OJ题:LeetCode--206.反转链表

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;今天给大家带来的是LeetCode中206题&#xff1a;反转链表 数 据 结 构&#xff1a;数据结构专栏 作 者&#xff1a;stackY、 C 语 言 &#xff1a;C语言专栏 LeetCode &#xff1a;LeetCode刷题训练营 LeetCod…

TiDB实战篇-数据库热点问题

形成热点的原因 主要是因为数据插入进去的时候是按顺序加数据的。 数据分裂以后还是在一个store上面&#xff0c;就会形成读写热点。 没有走索引全表扫描的情况。 定位热点 如果有热点&#xff0c;那么它的查询语句应该是比较多的&#xff0c;容易在这个地方找到对应的热点问…

Leetcode434. 字符串中的单词数

Every day a leetcode 题目来源&#xff1a;434. 字符串中的单词数 解法1&#xff1a;istringstream 我们知道&#xff0c;C默认通过空格&#xff08;或回车&#xff09;来分割字符串输入&#xff0c;即区分不同的字符串输入。 istringstream类用于执行C风格的串流的输入操…

Flowable入门

Flowable初体验 Flowable是什么 Flowable 是一个使用 Java 编写的轻量级业务流程引擎&#xff0c;常用于需要人工审批相关的业务&#xff0c;比如请假、报销、采购等业务。 为什么要使用工作流呢&#xff1f; 对于复杂的业务流程&#xff0c;通过数据库的状态字段难以控制和…

软考信管高级——质量管理

质量管理内容 质量保证QA(过程符合要求/过程改进&#xff09; (1)按项目计划开展质量活动&#xff0c;使项目过程和产品符合质量要求&#xff0c;即按计划做质量&#xff1b; (2)提高项目干系人对项目将要满足质量要求的信心&#xff1b; (3)按过程改进计划进行过程改进&…

金兰组织 | 2023金兰解决方案集经营管理篇正式发布

为助力企业创新管理、提质增效&#xff0c;人大金仓携手金兰组织成员单位&#xff0c;于近期发布多项经营管理领域的联合解决方案&#xff0c;共享创新应用成果。 /人大金仓高级副总裁宋瑞/ 人大金仓高级副总裁宋瑞在致辞中表示&#xff1a;“联合解决方案创新是指通过把不同领…

利用谷歌云Pub/Sub 实现多任务并行分发处理方案

背景 目前老梁团队负责的Global Data Integration Platform每天有大量文件需要从来自不同地区的上游下载文件并进行处理后再发送到不同下游。老梁的数据集成平台集群有6个服务器节点&#xff0c;老梁希望所有机器的资源都能利用上&#xff0c;提升大量文件并行处理能力&#x…

C# Microsoft.ClearScript.V8脚本使用

1、ClearScript支持的功能和适用场景 微软的.net是非常强大和灵活的&#xff0c;除了C#体系脚本扩展&#xff0c;也支持其他流行的脚本扩展&#xff0c;Microsoft.ClearScript.V8就是一个.NET绑定到Google V8的脚本引擎。它允许.NET应用程序直接从JavaScript代码中调用函数&am…

Redis布隆过滤器的原理和应用场景,解决缓存穿透

目录 专栏导读一、布隆过滤器BloomFilter是什么二、布隆过滤器BloomFilter能干嘛?三、布隆过滤器使用场景1、解决缓存穿透问题2、黑名单3、网页爬虫对URL的去重,避免爬取相同的URL地址四、操作布隆过滤器BloomFilter1、使用布隆过滤器2、删除key3、判断是否存在五、代码实例1…