机器学习比赛大杀器 ---- 模型融合 (stacking & blending)



转载请注明 AIQ - 最专业的机器学习大数据社区  http://www.6aiq.com

AIQ 机器学习大数据 知乎专栏 点击关注

_ 怎样赢得机器学习比赛:你拿别人的结果和你自己的结果与做集成。 _

—— Vitaly Kuznetsov NIPS2014。

集成模型是一种能在各种的机器学习任务上提高准确率的强有力技术。在这篇文章中,我会分享我在 Kaggle 比赛中的集成方法。

在第一部分中,我们会讨论从提交文件中建立集成。主要包括:

  • 投票集成

  • 平均

  • 排名平均

第二部分我们会讨论 通过 generalization/blending 等方法来创建集成。

我会在后续回答为什么集成能够减少泛化误差。最后我会展示不同的集成方法,包括它们的结果以及代码以供你自己去尝试。

对提交文件进行集成

最简单方便的办法就是对 Kaggle 提交的 csv 文件直接进行集成。你只需要模型在测试集上的预测结果,而不需要重新训练一个模型。它简单快速,只需使用已有模型的预测结果,是拼队的理想选择。

投票集成 (预测结果为类别时)

我们先看一下简单的投票集成方法。来看看为什么集成模型能够减少错误率,和为什么它能在模型间相关度较低时能取得更好的结果。

纠错码

在航天任务中,所有的信号都被正确的传达是非常重要的。

如果我们有一个二进制字符串形式的信号,如:

1110110011101111011111011011

如果信号在传输过程中有一位发生了翻转(第二位),变成了

1010110011101111011111011011

那这可能是致命的。

在纠错码中有一个编码 解决方案。在最简单的情况下,即纠错码是重复码时:以同样大小的数据块多次传递信号,并进行投票(以少数服从多数原则)。

Original signal:
1110110011


Encoded:

10,3 101011001111101100111110110011

Decoding:

101011001111101100111110110011

Majority vote:
1110110011

信号失真很少发生且通常在局部发生,因此,多次投票依然出错的可能性就更小了。

只要信号失真不是完全不可预测的(有 50% 的几率发生),信号就能被修复。

一个机器学习的例子

假设我们的测试集有 10 个样本,正确的情况应该都是 1:

1111111111

我们有 3 个正确率为 70% 的二分类器记为 A,B,C。你可以将这些分类器视为伪随机数产生器,以 70% 的概率产生”1”,30% 的概率产生”0”。

下面我们会展示这些伪分类器通过投票集成的方法得到 78% 的正确率。

涉及到一点数学

我们看到有 44% 的概率投票可以校正大部分错误。大部分投票集成会使最终的准确率变成 78% 左右 (0.3429 + 0.4409 = 0.7838)。

投票个数

跟重复码相似,随着编码重复次数的增加对错误的校正能力也会增加,因此集成通常可以通过提高集成成员的个数来提升准确率。

同样利用上面数学的数学公式:对 5 个有 70% 准确率的伪随机分类器进行投票集成会得到 83% 的准确率。在大约 66% 的情况下投票可以校正 1 或 2 个错误编码。(0.36015 + 0.3087)

相关性

在我第一次组队参加 2014 年 KDD 杯比赛时,Marios Michailidis (KazAnova) 提出了一些奇特的东西,他对我们所有的提交文件计算 皮尔逊相关系数,并且挑选出一些性能较好且相关系数较低的模型。

从这些挑选出来的文件中创建平均集成模型,给我们在排行榜上带来了巨大的提升,50 名的飞跃。不相关的预测结果的集成明显比相关的集成结果要好,这是为什么?

为了说明这一点,我们再举 3 个简单的模型。正确的情况仍然是全是 1:

Kaggle 案例:森林植被类型预测

当评价指标需要有力的预测时,比如多分类问题的准确率,少数服从多数投票法具有重要意义。

森林植被类型预测 比赛https://www.kaggle.com/c/forest-cover-type-prediction

使用 UCI Forest CoverType 数据集。这个数据集有 54 个属性,6 种分类类型。

https://archive.ics.uci.edu/ml/datasets/Covertype

我们建立一个有 500 棵树的随机森林模型作为 起始模型,然后我们再建立更多的模型,并挑选出最好的一个。在这个问题中,我们选择的一个 ExtraTreesClassifier 模型表现得最好。

加权

接下来,我们讨论加权投票。为什么要加权?通常我们希望模型越好,其权重就越高。所以,在这里,我们将表现最好的模型的投票看作 3 票,其它的 4 个模型只看作 1 票。

原因是:当表现较差的模型需要否决表现最好的模型时,唯一的办法是它们集体同意另一种选择。我们期望这样的集成能够对表现最好的模型进行一些修正,带来一些小的提高。

表一是 5 个模型训练出来的结果,包括结果得分以及加权的得分。

Kaggle 案例:CIFAR-10 图像检测

CIFAR-10 是另一个用准确率衡量的多分类 kaggle 比赛。

这个比赛中,我们队的队长 Phil Culliton,从 dr. Graham 那复制了一个好的模型,并第一个发现最好的参数设置。

然后他对大约 30 个提交文件使用了投票集成的方法 (所有的准确率得分在 90% 以上)。在集成模型中最好的单模型的得分为 0.93170.

对 30 个模型的投票集成得分为 0.94120. 大约降低了 0.01 错误率的,使得其识别结果超过人类 estimated human classification accuracy.

代码

我们有一个简单的投票脚本 

https://github.com/MLWave/Kaggle-Ensemble-Guide/tree/master/src

kaggle_vote.py

在 MLWave Github repo 中找到. 它在 kaggle 的提交目录中运行,并负责创建一个新的提交文件。更新:Armando Segnini 已经加上了加权部分的代码。

Ensembling. 训练 10 个神经网络并平均它们的预测结果,这是一个相当简单的技术,却有相当大的性能改进。

这里可能会有疑惑:为什么平均会有如此大的帮助?这有一个对于平均有效的简单的原因。假设我们有 2 个错误率 70% 的分类器,当 2 者结果一样时,那就是这个结果;当 2 者发生分歧时,那么如果其中一个分类器总是正确的,那么平均预测结果就会设置更多的权重在那个经常正确的答案上。

这个作用会特别强,whenever the network is confident when it’s right and unconfident when it’s wrong.——Ilya Sutskever 在深度学习的简单概述中说道。

平均

平均可以很好的解决一系列问题 (二分类与回归问题) 与指标(AUC, 误差平方或对数损失)。

与其说平均,不如说采用了多个个体模型预测值的平均。一个在 Kaggle 中经常听到的词是“bagging submissions”。

平均预测常常会降低过拟合。在类与类间,你想要理想的平滑的将其分离,而单一模型的预测在边界间可能会有一些粗糙。

上面这幅图片来自这个 kaggle 比赛:不要过拟合! 图中黑线比绿线有更好的分割,绿色线已经从数据点中学习了一些噪声。但不用担心,平均多个不同的绿线应该使我们更接近黑线。

记住,我们的目标不仅是去记住这些训练数据 (这里有比在随机森林里更加有效的方法来存储数据),而且还要去对我们没有看到的数据进行良好的泛化。

Kaggle 案例: Bag of Words Meets Bags of Popcorn

这是一个电影情感分析竞赛,在以前的文章中,我们使用 在线感知机脚本 

https://mlwave.com/online-learning-perceptron/

得到了 0.952 的 AUC.

这个感知机是一个线性分类器,在数据线性可分的情况下一定能找到一个分隔。这是一个受人喜欢的性质,但是你要意识到一旦达到这种分隔,分类器就会停止学习。它不一定会是新数据的最好的分隔。

那当我们随机初始化 5 个感知机的权重,并通过平均来组合预测会发生什么?结果是我们在测试集上的结果得到了提升,但这是为什么呢?

以上结果还能说明,集成能 (暂时) 使您不必了解特定机器学习算法的更精细的细节与内部工作原理。如果集成起作用,那很好,如果没起作用,那并无大碍。

就算你平均 10 个相同的线性回归的结果也没事。Bagging 一个糟糕的交叉验证与过拟合的提交有可能会增加多样性从而给你带来一点提高。

代码

我们已经在 Github 上发布了一个 平均脚本,

https://github.com/MLWave/Kaggle-Ensemble-Guide/tree/master/src

kaggle_avg.py

它以.csv 文件作为输入并得到一个平均的提交结果。

更新:Dat Le 已经添加了一个 几何平均的脚本。

kaggle_geomean.py

几何平均能比普通平均表现的更好。

排名平均

当平均多个来自不同模型的输出时,会出现一些问题。并不是所有的预测器的结果是完美 校准的, 它们可能会产生过高或过低的预测概率,或者预测在一定的范围里非常混乱。

在极端情况下, 你可能会有一个这样一个提交:

历史排名

排名需要一个测试集,所以当你要预测一个新样本时,你该怎么办?你可以与老的测试集一起,重新计算排名,但这会增加你的解决方案的复杂性。

一个解决方案是使用历史排名。存储旧的测试集预测及其排名,现在当你预测一个新的测试样例如“0.35000110”,你去找到最接近的历史预测并取其历史排名 (在这里最接近的历史预测是“0.35000111”其历史排名为“3”)。

Kaggle 使用案例:获得有价值的顾客挑战赛

排名平均在基于排名和基于阈值的指标 (如 AUC) 和搜索引擎质量指标 (如 k 平均精度) 上表现良好。

这个 挑战赛的目标 是对一个购物者成为一个重复顾客的概率进行排名。

https://www.kaggle.com/c/acquire-valued-shoppers-challenge

我们队首先将多个 Vowpal Wabbit 中的模型与一个 R 语言的 GLMNet 模型进行取平均,然后我们使用排名平均来提高完全相同的集成的情况。

我已经在 Avito 挑战赛中写过排名平均给了我们大幅的提升 。

finnally, when weighted rank averaging the bagged perceptrons from the previous chapter (1x) with the new bag-of-words tutorial (3x) on fastML.com we improve that model’s performance from 0.96328 AUC to 0.96461 AUC.

代码

排名平均脚本 已被添加到了 MLWave Github repos 上。

比赛是一种有效的方式,因为有无数的技术可以在建模问题上使用,但我们不能提前知道哪些将是最有效的。Anthony Goldbloom 在 Data Prediction Competitions — Far More than Just a Bit of Fun 上说。

Stacked Generalization & Blending

对预测文件进行平均既简单又好用,但这并不是顶级 kaggle 选手使用的唯一方法。stacking 与 blending 也能让你颇受收益。做好心理准备,接来下将要给你介绍屠龙技。

Netflix

Netdlix 公司曾组织并普及了第一次数据科学比赛, 在电影推荐挑战赛中,参赛者们将集成发展成为了一门艺术,可能是太极端了以至于 Netfilx 公司决定不将获胜方案应用到产品中。 因为这实施起来太复杂了。

不过,这个比赛涌现了很多论文与新颖的方法:

  • Feature-Weighted Linear Stacking

  • Combining Predictions for Accurate Recommender Systems

  • The BigChaos Solution to the Netflix Prize

这些论文都比较有趣且可以阅读的,当你想要提高你在 Kaggle 比赛中的成绩时,可以点进去阅读一下。

这是我工作这么多年以来,最令人印象深刻的集成和看到的最好的成果,它融合了上百个预测模型来得到最终结果。我们在线下使用了一些新方法重新评估了一番,但是我们测试认为该模型对准确率提升效果似乎并不值得将它引入到生产环境——-Netflix 的工程师说。

Stacked generalization

Wolpert 在 1992 的论文中对 stacked generalization 进行了介绍,比 Breiman 的论文 “Bagging Predictors“早了 2 年。Wolpert 的另一成名的机器学习理论是:“没有免费午餐定理”

stacked generalization 背后的基本思想是使用大量基分类器,然后使用另一种分类器来融合它们的预测,旨在降低泛化误差。

下面来说下 2 折 stacking:

  • 将训练集分成 2 部分: train_a 与 train_b

  • 用 train_a 来拟合一个初级学习器对 train_b 进行预测

  • 用 train_b 来拟合同类型的学习器对 train_a 进行预测

  • 最后用整个训练集拟合模型,并对测试集进行预测

  • 基于初级学习器的概率输出,来训练次级学习器

    一个 stacker 模型通过使用第一阶段的预测作为特征,比相互独立的训练模型能够得到更多的信息。

我们通常希望在第 0 层泛化器是全类型的,而不仅仅是彼此的简单变化 (比如我们想要 surface-fitters, Turing-machine builders, statistical extrapolators 等等.) 这样,所有可能学习到训练集规律的方法都会被使用到, 这就是所谓的初级学习器应该“跨越空间”意思的一部分.

[…]stacked generalization 是将非线性泛化器组合从而形成新的泛化器的手段,是为了尝试最好的集成每个初级泛化器。每个学习器信息越多 (在其他学习器上没有重复),stacked generalization 的结果就越好

Wolpert (1992) Stacked Generalization

Blending

Blending 一词是 Netflix 的获胜者们引入的。它与 stacked generalization 非常像,但更简单并且信息泄露风险更小。一些研究者们交换着使用“stacked ensembling”与“blending”这 2 个词。

通过 Blinding,不需要对训练集创建折外预测 (out-of-fold predictions),你只需创建一个小的留出集,比如 10% 的训练集做为留出。stacker 模型只在留出集里面进行训练。

Blending 的优势:

  • 比 stacking 更加简单

  • 能够防止信息泄露:generalizers 和 stackers 使用不同的数据

  • 你不需要跟你的队友设定一个相同的随机种子来进行相同的分折 谁都可以将模型放入“blender”中,由 blender 来决定是否保留这个模型。

缺点:

  • 只使用了整体中数据一部分

  • 最终的模型有可能对留出集过拟合

  • stacking 使用交叉验证比使用单一留出集更加稳健 (在更多的折上进行计算)。

至于性能,两种技术的得到的结果差不多,取决于你的个人喜好以及你更倾向于哪种技能。就我自己而言,我更喜欢 stacking。

如果你不能做选择的话,你可以同时选择这 2 种,使用 stacked 泛化器创建 stacked 集成和折外预测。然后使用留出集在第三层进一步结合这些 stacked 模型。

Stacking with logistic regression

使用逻辑斯谛回归做融合是一个非常经典的 stacking 方法。我找到一个脚本很好的帮助我理解了这一方法。

当创建一个用于预测的测试集时,你可以一次性完成该操作,或者利用折外估计的模型 (out-of-fold predictors) 完成。当然为了减少模型和代码的复杂性,我更倾向于一次性完成。

kaggle 案例:“Papirusy z Edhellond”

在这个比赛中,我使用上面的 blend.py 脚本,结合了 8 个模型(不同评价指标的 ET RF GMB),然后使用逻辑斯谛回归给了我第 2 名的成绩。

Kaggle 案例: KDD-cup 2014

使用这个脚本,我将 Yan XU 的 AUC 评分从 0.605 提高到了 0.625。

Stacking with non-linear algorithms

目前流行用于 Stacking 的非线性算法有 GBM,KNN,NN,RF 和 ET。

非线性的 Stacking 在多分类任务中,使用原始特征就能产生令人惊讶的提升。显然,在第一阶段中的预测提供了非常丰富的信息并得到了最高的特征重要性。非线性算法有效地找到了原始特征与元模型特征之间的关系。

Kaggle 案例: TUT Headpose Estimation Challenge

在 TUT Headpose Estimation 比赛中,可以当做是一个多分类,多标签的问题。

对于每一个标签,将分别训练一个独立的集成模型。

接下来的表格显示了每个独立模型的得分表现,以及当他们使用 extremely randomized trees 来做 stacking 时提高的得分。

我们看到使用了 stack 后,误差减少了将近 30%

有兴趣的可以在 Computer Vision for Head Pose Estimation: Review of a Competition 看到这一结果的论文。

代码

你可以在 out-of-fold probability predictions 的 MLWave Github repo 中找到一个函数去使用 out-of-fold probability predictions。你也可以使用 numpy horizontal stacking (hstack) 去创建融合数据。

Feature weighted linear stacking

t 线性加权 stacking 就是,先将提取后的特征用各个模型进行预测,然后使用一个线性的模型去学习出哪个个模型对于某些样本来说是最优的,通过将各个模型的预测结果加权求和完成。使用线性的算法可以非常简单快捷地去验证你的模型,因为你可以清楚地看到每个模型所分配的权重。

Vowpal Wabbit 对于线性加权 stacking 提出了一种创新性的用法。比如我们有以下训练集,它有两个特征空间,一个是 f,一个是 s:

1 |f f_1:0.55 f_2:0.78 f_3:7.9 |s RF:0.95 ET:0.97 GBM:0.92

我们可以通过-q fs来构造二次方的特征,它是 s-特征空间f-特征空间的交互项。在f-特征空间中的特征可以是原始的特征,也可以是例子中的元特征。

Quadratic linear stacking of models

这方法并没有名字,所以我给他造了一个。这方法跟线性 stacking 非常像,但它在线性的基础上,额外构造了一系列模型之间预测结果的组合。这一方法在许多次实验中都对评分有很大的提高。最值得提到的是在 DrivenData 上的比赛: Modeling Women’s Healthcare Decision competition

我们同样使用之前提到的 VW 训练集:

1 |f f_1:0.55 f_2:0.78 f_3:7.9 |s RF:0.95 ET:0.97 GBM:0.92

我们可以使用-q ss 训练从而创建出 s- 特征空间中模型预测之间的二阶特征交互项 (如 RF*GBM)。

它与线性加权 stacking 可以非常简单地结合起来,比如说先算 f 和 s 的交互项,再加上 s 和 s 的交互项:-q fs -q ss

So now you have a case where many base models should be created. You don’t know apriori which of these models are going to be helpful in the final meta model. In the case of two stage models, it is highly likely weak base models are preferred.

So why tune these base models very much at all? Perhaps tuning here is just obtaining model diversity. But at the end of the day you don’t know which base models will be helpful. And the final stage will likely be linear (which requires no tuning, or perhaps a single parameter to give some sparsity). Mike KimTuning doesn’t matter. Why are you doing it?

Stacking 分类和回归

Stacking 可以允许你使用分类器来完成回归问题,反之亦然。比如说,在一个二分类问题中,有人可能会尝试使用线性分位回归 来完成分类任务。一个好的 stacker 应该可以从预测中提取出你想要的信息,尽管回归通常并不是一个好的分类器。

而使用一个分类器做回归就有点棘手。你先离散化:将 y 均匀地分为几个的类别。那么一个要求你预测工资的回归问题就可以转换为这样的一个多分类的问题:

  • 所有低于 20k 的为类别 1

  • 所有 20k 到 40k 之间的为类别 2

  • 所有大于 40k 的为类别 3

使用分类器预测出来的概率可以帮助回归函数取得更好的预测效果。

Stacking 无监督特征学习

没有任何人说过我们使用 stacking 的时候一定要是有监督的。事实上你可以使用 stacking 技术来处理无监督学习的问题。

k-means 聚类是最为流行的无监督算法。Sofia-ML 实现了一个快速的在线 k-means 算法适用于这里。

其他有意思的方法是 t-SNE:通过把数据降维 2 到 3 维,然后将它放到非性融合器来融合。使用留出集的方法感觉上是最安全的选择。可以看看由 Mike Kim 提出的解决方案,他使用了 t-SNE 向量,然后结合了 xgboost: 0.41599 via t-SNE meta-bagging

Piotr 给出的 t-SNE 在分类任务中的可视化表现

Online Stacking

我花了大量时间去研究一个叫 online stacking 的想法:首先从一个哈希二值映射中创建一个小型的随机树。如果树预测正确则增加其收益,反之减少其收益。然后我们将收益最大的树,和收益最小树的预测作为特征。

它确实有效,然而只限于人造的数据,它确实可以把异或问题 (XOR-problem) 学习出来。但是它没有在任何真实数据集上成功过,相信我,我已经试过了。所以,从此之后,对于只使用人造数据去验证它们的新算法的论文,我都会持怀疑的态度。

一个相似的想法在一篇论文中是有效的: random bit regression。在这里,从特征中构造了多个随机的线性函数,最好的函数是由很强的正则项中产生的。这个方法我曾经在一些数据集上成功过。这会是我将来发表的主题。

一个 (半)online stacking 更加具体的例子是广告点击预测问题。模型会在用户近期行为的数据中预测更准,也就是当数据集具有时间效应的时候,你可以使用 Vowpal Wabbit 去训练整个数据集,并使用一个更加复杂的工具比如说 xgboost 去训练最后几天的数据。你只需将 xgboost 的结果与样本进行堆叠 (stack),并让 Vowpal Wabbit 尽其所能:优化损失函数。

The natural world is complex, so it figures that ensembling different models can capture more of this complexity. Ben Hamner ‘Machine learning best practices we’ve learned from hundreds of competitions’ (video)

一切皆为超参数 (hyper-parameter)

当我们使用 stacking/blending/meta-modeling 时,一个良好的想法就是所有的行为都是融合模型的参数。

比如说:

  • 不标准化数据

  • 使用 z 标准化

  • 使用 0-1 标准化

这些都是可以去调从而提高集成的效果。同样的,使用多少个基模型的数量也是可以去调整优化的。特征选择(前 70%)或数据填补(缺失填补)也是一系列的参数。

使用随机网格搜索就是一个比较好的调参方法,它在调整这些参数的时候确实是有起到作用的。

模型选择

你还可以通过组合多个集成模型来继续优化你评分。

  • 这有一个特别的方法:使用平均,投票,或秩平均等方法来手动选择表现好的集成模型。

  • 贪婪前向模型选择 (Caruana et al.)。先使用一个或几个好的模型作为基集成模型。然后不断地增加使得评分提升最大的模型。当然你也可以在期间允许把模型放回去,这样的话一个模型可能会被选择很多次。

  • 使用遗传算法来做选择,用交叉验证得分作为适应度评分函数。可以看 inversion‘s solution 的解决方案:‘Strategy for top 25 position‘.

  • 受 Caruana 的启发,我使用一个完全随机的方法:通过随机选择集成 (无放回),创建一个 100 或其他个数的集成。然后选择其中评分最高的模型。

自动化操作

当我在 Otto product classification 比赛中,使用了 stacking 策略,我很快的得到了前十的成绩。我通过不断的添加越来越多的基分类器,和 bagging 多个 stack 集成我的分数得到不断的提高。

当我达到了 7 个基模型,用了 6 个 stacker,一阵恐惧和忧郁的感觉向我袭来。我是否能够把所有这些都重现?这些复杂而又笨重的模型让我偏离了快速而又简单的机器学习的初衷。

我在后续的比赛中,都将时间花在了建造一个自动化 stacking 的方法。我们去训练那些具有纯随机参数的纯随机算法的基模型。我们写了一个与 Scikit-learn 的 Api 协同工作的封装器去负责训练分类模型 VW, Sofia-ML, RGF, MLP and XGBoost。

并行自动 stacker 的草稿

使用自动化 stacking 可以让你轻松的打败那些对该问题设计特定算法的领域专家,各个模型的训练都是可以分布式和并行化的。

你也可以在这里看到自动化融合的代码:MLWave Github repo: “Hodor-autoML“.

在 Otto product 分类比赛中,第 1 名和第 2 名融合了超过 1000 个不同的模型 可以在这里看到更多: first place 和 second place。

我们为什么要使用如此复杂的集成方法?

使用 stacking,组合 1000 多个模型,计算几十个小时这也太疯狂了吧。这.. 确实是的。但是,这些怪物般的集成方法同样有着它的用处:

  • 它可以使你赢得 kaggle 比赛

  • 它可以帮你打败当前学术界性能最好的算法

  • You can then compare your new-and-improved benchmark with the performance of a simpler, more production-friendly model

  • 总有一天,虽然现在的计算机和云端还是很弱。你将做好准备

  • 我们有可能将集成的知识迁移到到简单的分类器上 (Hinton’s Dark Knowledge, Caruana’sModel Compression)

  • 不是所有基模型都要按时完成的。因为在集成方法中,即使损失一两个模型也是可以接受的。

  • 自动化的大型集成策略可以通过添加正则项有效的对抗过拟合,而且并不需要太多的调参和特征选择。所以从原则上讲,stacking 非常适合于那些“懒人”

  • 这是目前提升机器学习效果最好的方法,或者说是最效率的方法 human ensemble learning

  • 每 1% 精度的提升,或许就可以使得你的投资减少大量的损失。更严肃的说:在医疗行业中,每 1% 的提升,你就能多拯救几个生命。

这一论文的代码在:https://github.com/MLWave/Kaggle-Ensemble-Guide 上

https://blog.csdn.net/a358463121/article/details/53054686#t18

参考文献链接

英文版本 
http://mlwave.com/kaggle-ensembling-guide/ 

这个是上面英文翻译过来的汉语翻译版本 
kaggle 比赛集成指南 
http://m.blog.csdn.net/article/details?id=53054686

搜狗比赛第五名的 stacking 思路 
http://prozhuchen.com/2016/12/28/CCF%E5%A4%A7%E8%B5%9B%E6%90%9C%E7%8B%97%E7%94%A8%E6%88%B7%E7%94%BB%E5%83%8F%E6%80%BB%E7%BB%93/

kaggle 官方博客 stacking 融合 
http://blog.kaggle.com/2016/12/27/a-kagglers-guide-to-model-stacking-in-practice/

汉语版翻译如下

Kaggler 的“实践中模型堆叠指南”

介绍 
堆叠(也称为元组合)是用于组合来自多个预测模型的信息以生成新模型的模型组合技术。通常,堆叠模型(也称为二级模型)因为它的平滑性和突出每个基本模型在其中执行得最好的能力,并且抹黑其执行不佳的每个基本模型,所以将优于每个单个模型。因此,当基本模型显著不同时,堆叠是最有效的。关于在实践中怎样的堆叠是最常用的,这里我提供一个简单的例子和指导。

本教程最初发布在 Ben 的博客 GormAnalysis 上。

https://github.com/ben519/MLPB/tree/master/Problems/Classify+Dart+Throwers

请随意借鉴本文中使用的来自机器学习问题参考书的相关代码和数据集。

另外的 python 版本的 blending

https://github.com/emanuele/kaggle_pbr

动机 
假设有四个人在板子上投了 187 个飞镖。对于其中的 150 个飞镖,我们可以看到每个是谁投掷的以及飞镖落在了哪。而其余的,我们只能看到飞镖落在了哪里。我们的任务就基于它们的着陆点来猜测谁投掷的每个未标记的飞镖。

K 最近邻(基本模型 1) 
让我们使用 K 最近邻模型来尝试解决这个分类问题。为了选择 K 的最佳值,我们将使用 5 重交叉验证结合网格搜索,其中 K =(1,2,… 30)。在伪代码中: 
1. 将训练数据分成五个大小相等的数据集。调用这些交叉测试。 
2. 对于 K = 1,2,… 10 
1. 对于每个交叉测试 
1. 组合其他四个交叉用作训练交叉 
2. 在训练交叉上使用 K 最近邻模型(使用 K 的当前值) 
3. 对交叉测试进行预测,并测量所得预测的准确率 
2. 从五个交叉测试预测中计算平均准确率 
3. 保持 K 值具有最好的平均 CV 准确率 
使用我们的虚构数据,我们发现 K = 1 具有最佳的 CV 性能(67%的准确性)。使用 K = 1,我们现在训练整个训练数据集的模型,并对测试数据集进行预测。 最终,这将给我们约 70%的分类精度。

支持向量机(基本型 2) 
现在让我们再次使用支持向量机解决这个问题。此外,我们将添加一个 DistFromCenter 功能,用于测量每个点距板中心的距离,以帮助使数据线性可分。 使用 R 的 LiblineaR 包,我们得到两个超参数来调优: 
类型 
1.L2- 正则化 L2 丢失支持向量分类(双重) 
2.L2 正则化 L2 丢失支持向量分类(原始) 
3.L2- 正则化 L1 损失支持向量分类(双重) 
4.Crammer 和 Singer 的支持向量分类 
5.L1 正则化 L2 丢失支持向量分类 
成本 
正则化常数的倒数 
我们将测试的参数组合网格是 5 个列出的 SVM 类型的笛卡尔乘积,成本值为(.01,.1,10,100,1000,2000)。 那是

使用与我们的 K 最近邻模型相同的 CV + 网格搜索方法,这里我们找到最好的超参数为 type = 4,cost = 1000。再次,我们使用这些参数训练的模型,并对测试数据集进行预测。这将在测试数据集上给我们约 61%的 CV 分类精度和 78%的分类准确性。

堆叠(元组合)

让我们来看看每个模型分为 Bob,Sue,Mark 或 Kate 的板区域。 

不出所料,SVM 在分类 Bob 的投掷和 Sue 的投掷方面做得很好,但是在分类 Kate 的投掷和 Mark 的投掷方面做得不好。对于最近邻模型,情况正好相反。 提示:堆叠这些模型可能会卓有成效。 
一共有几个思考如何实现堆叠的派别。在我们的示例问题中我是根据自己的喜好来应用的: 
1. 将训练数据分成五个交叉测试

2. 创建一个名为“train_meta”的数据集,其具有与训练数据集相同的行 ID 和交叉 ID、空列 M1 和 M2。 类似地,创建一个名为“test_meta”的数据集,其具有与测试数据集相同的行 ID、空列 M1 和 M2 

3. 对于每个交叉测试 
{Fold1,Fold2,… Fold5} 
3.1 组合其他四个交叉用作训练交叉 

3.2 对于每个基本模型 
M1:K- 最近邻(k = 1) 
M2:支持向量机(type = 4,cost = 1000) 
3.2.1 将基本模型交叉训练,并在交叉测试进行预测。 将这些预测存储在 train_meta 中以用作堆叠模型的特征 
train_meta 与 M1 和 M2 填补 fold1

4. 将每个基本模型拟合到完整训练数据集,并对测试数据集进行预测。 将这些预测存储在 test_meta 内 

5. 使用 M1 和 M2 作为特征,将新模型 S(即,堆叠模型)适配到 train_meta,可选地,包括来自原始训练数据集或特征工程的其他特征。 
S:逻辑回归(来自 LiblineaR 包,类型 = 6,成本 = 100)。 适配 train_meta 
6. 使用堆叠模型 S 对 test_meta 进行最终预测 
test_meta 与堆叠模型预测

主要观点是,我们使用基础模型的预测作为堆叠模型的特征(即元特征)。 因此,堆叠模型能够辨别哪个模型表现良好,哪个模型表现不佳。还要注意的是,train_meta 的行 i 中的元特征不依赖于行 i 中的目标值,因为它们是在使用基本模型拟合过程中排除 target_i 的信息中产生的。 

或者,我们可以在测试数据集适合每个交叉测试之后立即使用每个基本模型进行预测。 在我们的例子中,这将产生五个 K- 最近邻模型和五个 SVM 模型的测试集预测。然后,我们将平均每个模型的预测以生成我们的 M1 和 M2 元特征。 这样做的一个好处是,它比第一种方法耗时少(因为我们不必在整个训练数据集上重新训练每个模型)。 它也有助于我们的训练元特征和测试元特征遵循类似的分布。然而,测试元 M1 和 M2 在第一种方法中可能更准确,因为每个基础模型在全训练数据集上训练(相对于训练数据集的 80%,在第二方法中为 5 次)。 

堆栈模型超参数调优
那么,如何调整堆叠模型的超参数? 关于基本模型,就像我们以前做的,我们可以使用交叉验证 + 网格搜索调整他们的超参数。 我们使用什么交叉并不重要,但使用我们用于堆叠的相同交叉通常很方便。调整堆叠模型的超参数是让事情变得有趣的地方。在实践中,大多数人(包括我自己)只需使用交叉验证 + 网格搜索,使用相同的精确 CV 交叉用于生成元特征。 这种方法有一个微妙的缺陷 - 你能找到它吗? 

事实上,在我们的堆叠 CV 过程中有一点点数据泄漏。 想想堆叠模型的第一轮交叉验证。我们将模型 S 拟合为 {fold2,fold3,fold4,fold5},对 fold1 进行预测并评估效果。但是{fold2,fold3,fold4,fold5} 中的元功能取决于 fold1 中的目标值。因此,我们试图预测的目标值本身就嵌入到我们用来拟合我们模型的特征中。这是泄漏,在理论上 S 可以从元特征推导出关于目标值的信息,其方式将使其过拟合训练数据,而不能很好地推广到袋外样本。 然而,你必须努力工作来想出一个这种泄漏足够大、导致堆叠模型过度拟合的例子。 在实践中,每个人都忽略了这个理论上的漏洞(坦白地说,我认为大多数人不知道它甚至存在!) 

堆叠模型选择和特性

你如何知道选择何种型号作为堆叠器以及元特征要包括哪些功能? 在我看来,这更像是一门艺术而不是一门科学。 你最好的办法是尝试不同的东西,熟悉什么是有效的,什么不是。另一个问题是,除了元特征,你应该为堆叠模型包括什么其他功能(如果有)?这也是一种艺术。看看我们的例子,很明显,DistFromCenter 在确定哪个模型将会很好地发挥作用。KNN 似乎在分类投掷于中心附近的飞镖上做得更好,SVM 模型在分类远离中心的飞镖上表现得更好。 让我们来看看使用逻辑回归来堆叠我们的模型。 我们将使用基本模型预测作为元特征,并使用 DistFromCenter 作为附加功能。 

果然,堆叠模型的性能优于两种基本模型 - 75%CV 精度和 86%测试精度。 就像我们对基本模型一样,现在让我们来看看它的覆盖训练数据的分类区域。 

这里的好处是,逻辑回归堆叠模型捕获每个基本模型的最好的方面,这就是为什么它的执行优于任何孤立的基本模型。 

实践中的堆叠 
为了包装,让我们来谈谈如何、何时、以及为什么在现实世界中使用堆叠。 就个人而言,我大多在 Kaggle 的机器学习竞赛中使用堆叠。一般来说,堆叠产生小的收益与大量增加的复杂性不值得为大多数企业使用。 但堆叠几乎总是富有成果,所以它几乎总是用于顶部 Kaggle 解决方案。 事实上,当你有一队人试图在一个模型上合作时,堆叠对 Kaggle 真的很有效。采用一组单独的交叉,然后每个团队成员使用那些交叉建立他们自己的模型。 然后每个模型可以使用单个堆叠脚本组合。这是极好的,因为它防止团队成员踩在彼此的脚趾,尴尬地试图将他们的想法拼接到相同的代码库。 

最后一位。 假设我们有具有(用户,产品)对的数据集,并且我们想要预测用户在购买给定产品的情况下,他 / 她与该产品一起展示广告的几率。一个有效的功能可能是,使用培训数据,有多少百分比的产品广告给用户,而他实际上在过去就已经购买?因此,对于训练数据中的样本(user1,productA),我们要解决一个像 UserPurchasePercentage 这样的功能,但是我们必须小心,不要在数据中引入泄漏。 我们按照接下来这样做: 

1. 将训练数据拆分成交叉 
2. 对于每个交叉测试 
1. 标识交叉测试中的唯一一组用户 
2. 使用剩余的交叉计算 UserPurchasePercentage(每个用户购买的广告产品的百分比) 

3. 通过(fold id,用户 id)将 UserPurchasePercentage 映射回培训数据 
现在我们可以使用 UserPurchasePercentage 作为我们的梯度提升模型(或任何我们想要的模型)的一个特性。我们刚刚做的是有效地建立一个预测模型,基于 user_i 在过去购买的广告产品的百分比,预测他将购买 product_x 的概率,并使用这些预测作为我们的真实模型的元特征。这是一个微妙而有效并且我经常在实践和 Kaggle 实现的有效的堆叠形式 - 。

https://blog.csdn.net/a358463121/article/details/53054686#t18

https://blog.csdn.net/u014356002/article/details/54376138


更多高质资源 尽在AIQ 机器学习大数据 知乎专栏 点击关注

转载请注明 AIQ - 最专业的机器学习大数据社区  http://www.6aiq.com