百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

Boosting,Bagging和Stacking-使用sklearn和mlens的集成方法

toyiye 2024-06-21 12:31 17 浏览 0 评论

Binning、bagging和stacking是数据科学家工具包,也是一系列称为集成方法的统计技术的一部分。

有三个主要术语描述各种模型的集成(组合)到一个更有效的模型:

  • Bagging 以减少模型的方差;
  • Boosting降低模型的偏差;
  • Stacking以 增加分类器的预测力。

什么是集成方法?

这里的想法是训练多个模型,每个模型的目标是预测或分类一组结果。

模型学习中的大多数错误来自三个主要因素:方差、噪声和偏差。通过使用集成方法,我们能够提高最终模型的稳定性并减少前面提到的错误。通过组合许多模型,我们能够(大部分)减少方差,即使它们各自不是很好,因为我们不会受到来自单个源的随机错误的影响。

集成建模的主要原理是将弱学习者集中在一起形成一个强学习者。

考虑一下,我将在下面展示房屋价格,以及你如何考虑将一个人的房子的价格分类为低,中,或高。你会用一条规则来确定这个分类吗?或者你会根据不同的因素使用不同的规则吗?

你当然会使用各种规则,例如:

  • 步行至公立学校;
  • 房屋的年代和预期的翻修;
  • 后院有多大;
  • 开车去城市的时间和交通的便利性等。

正如这几个问题不能通过一个分析来解决,而是通过不同的和重叠的分析方法来解决。这是集成建模的核心。

住房数据集

以下示例查看住房数据,以查看房屋的价格分类(低,中,高)是否可以通过以下几个特征来确定:

  • The lot size;
  • No. of bedrooms;
  • No. of bathrooms;
  • No. of stories;
  • Has driveway, etc.

使用pydataset的住房数据来表示我们的各种集成方法在分类精度上的差异。需要注意的是,我认为这是一个很好的数据集,但是有太多的二进制变量。如果我回去重做这个项目,我可能会使用Boston housing dataset,它有更多的地理定位特性工程的特性和灵活性。

让我们来看看我们的数据,Python代码如下:

from pydataset import data

# Get the housing data

df = data('Housing')

df.head().values

# Check the data

array([[42000.0, 5850, 3, 1, 2, 'yes', 'no', 'yes', 'no', 'no', 1, 'no'],

[38500.0, 4000, 2, 1, 1, 'yes', 'no', 'no', 'no', 'no', 0, 'no'],

[49500.0, 3060, 3, 1, 1, 'yes', 'no', 'no', 'no', 'no', 0, 'no'], ...

# Create dictionary to label 'yes' and 'no'

d = dict(zip(['no', 'yes'], range(0,2)))

for i in zip(df.dtypes.index, df.dtypes):

if str(i[1]) == 'object':

df[i[0]] = df[i[0]].map(d)

在我们讨论价格之前,先看看价格的范围

for i, j in enumerate(np.unique(pd.qcut(df['price'], 3))):

print i, j

# Results

0 (24999.999, 53000.0]

1 (53000.0, 74500.0]

2 (74500.0, 190000.0]

看起来我们的数据集中最低的房子是25K美元,最高的是190K美元。虽然不是市面上最贵的房子,但对于下面的例子来说就足够了。现在我们来讨论一下价格。

df[‘price’] = pd.qcut(df[‘price’], 3, labels=[‘0’, ‘1’, ‘2’]).cat.codes

# Split into two sets

y = df['price']

X = df.drop('price', 1)

现在我们有事情要处理了。它应该足以说明集成模型的力量。

本文不打算对任何数据进行探究,但是让我们看一下快速的相关图,看看我们正在为住房数据做什么。

住房数据的相关图

这里没有什么有趣的东西,除了看起来像房子的stories 增加了地下室的机会减少了。车道和卧室的情况也是如此,但也只有一点点。

为了完整起见,这是上面的热图显示的一些更有趣的关系的成对图。

数据的选定部分的成对图

Bagging

引入的第一个术语bagging是Bootstrapping 和aggregating的结合的简写。Bootstrapping是一种帮助减少分类器的方差和减少过度拟合的方法,通过从训练集中重新采样数据,该训练集中的基数与原始集合相同。

一个模型的高方差是不好的,表明它的性能对所提供的训练数据是敏感的。因此,即使提供了更多的训练数据,模型也可能表现不佳。甚至不能减少模型的方差。

当你有有限的数据时,bagging是一种有效的方法,通过使用样本,你可以通过对许多样本的分数进行汇总得到一个估计。

bagging最简单的方法是使用几个小的子样本并将它们bag,如果集成精度比基本模型高得多,它就会工作;如果不是,使用较大的子样本。

# Bagging RandomForestClassifier at different subsamples

# Bagging classifier at .1 subsamples

Avg. Accuracy of: 0.641 (+/-) 0.080

# Bagging classifier at .3 subsamples

Avg. Accuracy of: 0.650 (+/-) 0.091 # Better accuracy

# Bagging classifier at .5 subsamples

Avg. Accuracy of: 0.639 (+/-) 0.091 # Worse accuracy

注意,使用较大的子样本不能保证改进结果。在bagging中,在基本模型精度和通过bagging获得的增益之间进行权衡。当您有一个不稳定的模型时,bagging可以极大地改善集合,但是当您的基础模型更稳定时——训练在更大的子样本上,具有更高的精度——bagging的改进减少了。

一旦bagging完成,所有模型都创建在(大部分)不同的数据上,然后使用加权平均来确定最终的分数。

# Get some classifiers to evaluate

from sklearn.model_selection import cross_val_score

from sklearn.ensemble import BaggingClassifier, ExtraTreesClassifier, RandomForestClassifier

from sklearn.neighbors import KNeighborsClassifier

from sklearn.linear_model import RidgeClassifier

from sklearn.svm import SVC

seed = 1075

np.random.seed(seed)

# Create classifiers

rf = RandomForestClassifier()

et = ExtraTreesClassifier()

knn = KNeighborsClassifier()

svc = SVC()

rg = RidgeClassifier()

clf_array = [rf, et, knn, svc, rg]

for clf in clf_array:

vanilla_scores = cross_val_score(clf, X, y, cv=10, n_jobs=-1)

bagging_clf = BaggingClassifier(clf,

max_samples=0.4, max_features=10, random_state=seed)

bagging_scores = cross_val_score(bagging_clf, X, y, cv=10,

n_jobs=-1)

print "Mean of: {1:.3f}, std: (+/-) {2:.3f [{0}]"

.format(clf.__class__.__name__,

vanilla_scores.mean(), vanilla_scores.std())

print "Mean of: {1:.3f}, std: (+/-) {2:.3f} [Bagging {0}]\n"

.format(clf.__class__.__name__,

bagging_scores.mean(), bagging_scores.std())

我们的bagging和我们分类器的vanilla 版有什么不同?

Mean of: 0.632, std: (+/-) 0.081 [RandomForestClassifier]

Mean of: 0.639, std: (+/-) 0.069 [Bagging RandomForestClassifier]

Mean of: 0.636, std: (+/-) 0.080 [ExtraTreesClassifier]

Mean of: 0.654, std: (+/-) 0.073 [Bagging ExtraTreesClassifier]

Mean of: 0.500, std: (+/-) 0.086 [KNeighborsClassifier]

Mean of: 0.535, std: (+/-) 0.111 [Bagging KNeighborsClassifier]

Mean of: 0.465, std: (+/-) 0.085 [SVC]

Mean of: 0.535, std: (+/-) 0.083 [Bagging SVC]

Mean of: 0.639, std: (+/-) 0.050 [RidgeClassifier]

Mean of: 0.597, std: (+/-) 0.045 [Bagging RidgeClassifier]

除了一个分类器外,所有的分类器的方差都较低。同样,除了我们的脊分类器,我们的分类器的精度都增加了。看起来这个bagging的东西确实有用。

所以我们的bagged分类器(大部分)更好,但是我们选择哪一个呢?

如何选择

Sklearn的VotingClassifier允许您组合不同的机器学习分类器,并对预测的类标签对记录进行投票。

对于分类器,有两种投票方式:hard 和soft。

对于hard投票,你只需要大多数分类器来决定结果。如下图所示,各种bagged模型用H表示,分类器的结果显示在行上。在最右边,H1和H3投票给第一个记录为“no”(紫色),H2投票给“yes”(黄色)。因为有2个模型投了“no”的票,所以集成团队将该记录归类为“no”。

使用soft(加权),我们使用每个分类器计算百分比权重。收集每个记录的每个模型的预测类概率,并乘以分类器权重,最后进行平均。然后从具有最高平均概率的类标签导出最终的类标签。

实际上,如果你只是提供你认为应该加权或减少加权的模型的最佳猜测,很难找到权重。可以构建线性优化方程或神经网络以找到每个模型的正确加权以优化整体的准确性。

# Example of hard voting

from sklearn.ensemble import VotingClassifier

clf = [rf, et, knn, svc, rg]

eclf = VotingClassifier(estimators=[('Random Forests', rf), ('Extra Trees', et), ('KNeighbors', knn), ('SVC', svc), ('Ridge Classifier', rg)], voting='hard')

for clf, label in zip([rf, et, knn, svc, rg, eclf], ['Random Forest', 'Extra Trees', 'KNeighbors', 'SVC', 'Ridge Classifier', 'Ensemble']):

scores = cross_val_score(clf, X, y, cv=10, scoring='accuracy')

print("Accuracy: %0.2f (+/- %0.2f) [%s]" % (scores.mean(), scores.std(), label))

# Results

Mean: 0.627, std: (+/-) 0.082 [Random Forest]

Mean: 0.632, std: (+/-) 0.084 [Extra Trees]

Mean: 0.500, std: (+/-) 0.086 [KNeighbors]

Mean: 0.465, std: (+/-) 0.085 [SVC]

Mean: 0.639, std: (+/-) 0.050 [Ridge Classifier]

Mean: 0.641, std: (+/-) 0.094 [Ensemble]

# Compare this to the bagged results

Mean: 0.661, std: (+/-) 0.099 [Bagging Random Forest]

Mean: 0.650, std: (+/-) 0.082 [Bagging Extra Trees]

Mean: 0.535, std: (+/-) 0.117 [Bagging KNeighbors]

Mean: 0.528, std: (+/-) 0.068 [Bagging SVC]

Mean: 0.604, std: (+/-) 0.046 [Bagging Ridge Classifier]

Mean: 0.658, std: (+/-) 0.091 [Bagging Ensemble]

通过我们的bagged集成结果,我们提高了准确度(.658相对 .641)和方差(.091相对 .094)的减少,因此在我们将所有各种模型合并为一个之后,我们的集成模型正如预期的那样工作。

决策边界

现在我们已经知道我们的模型在单独和一起做得多好。我们如何看待分类器的边界并确定它们的截止点在哪里?

幸运的是,mlxtend有一个plot_decision_regions,显示每个分类器如何做出决定。因为在每个分类的决策过程中都有两个以上的特性,下面的图仅仅显示了lotsize和story的决策边界。

我们将使用eclf我们在项目的前一个投票阶段中定义的分类器,并使用分类结果将自己与我们之前vanilla模型进行比较。

以下是如何重新创建图表的Python实现方法

import matplotlib.pyplot as plt

from mlxtend.plotting import plot_decision_regions

import matplotlib.gridspec as gridspec

import itertools

gs = gridspec.GridSpec(3, 3)

fig = plt.figure(figsize=(14, 12))

labels = ['Random Forest', 'Extra Trees', 'KNN', 'Support Vector',

'Ridge Reg.', 'Ensemble']

for clf, lab, grd in zip([rf, et, knn, svc, rg, eclf],

labels,

itertools.product([0, 1, 2], repeat = 2)):

clf.fit(X[['lotsize', 'stories']], y)

ax = plt.subplot(gs[grd[0], grd[1]])

fig = plot_decision_regions(X=np.array(X[['lotsize', 'stories']]),

y=np.array(y), clf=clf)

plt.title(lab)

Boosting

考虑函数在函数空间上的优化,其中的优化可以使用梯度下降法来解决。Vanilla 梯度梯度下降用于最小化一组参数。例如,通过从误差函数的更新找到线性回归的参数的权重。

如果我们有一个光滑的凸参数空间,那么参数估计就显得微不足道,但是并不是所有的问题都能提供这样一个简单的平面来遍历。我们的问题是,因为有许多分类和二元变量,它创建了一个复杂的梯度,在优化过程中会遇到许多局部最小值。对于这些问题,我们可以使用一种不同的形式的梯度下降,叫做Boosting。

Boosting的主要思想是按顺序为整个集合模型添加其他模型。以前使用bagging,对创建的每个单独模型进行平均。这次每次迭代Boosting,创建一个新模型,并从先前学习者的误差中训练(更新)新的基础学习者模型。

该算法创建多个弱模型,其输出被加在一起以获得整体预测。这是早期的集成建模。现在boosted 梯度将当前预测移动到真实目标,其方式与梯度下降向真实值的移动方式类似。梯度下降优化发生在变化模型的输出上,而不是它们各自的参数。

有不同的方法来优化boosting算法,但它们超出了本文的范围。

与上面的bagging示例不同,经典的增强子集创建不是随机的,性能将取决于先前模型的性能。因为,迭代的每个新子集包含可能被先前模型误差分类的元素。我们还将使用我们之前使用的相同的hard投票来将模型组合在一起。

ada_boost = AdaBoostClassifier()

grad_boost = GradientBoostingClassifier()

xgb_boost = XGBClassifier()

boost_array = [ada_boost, grad_boost, xgb_boost]

eclf = EnsembleVoteClassifier(clfs=[ada_boost, grad_boost, xgb_boost], voting='hard')

labels = ['Ada Boost', 'Grad Boost', 'XG Boost', 'Ensemble']

for clf, label in zip([ada_boost, grad_boost, xgb_boost, eclf], labels):

scores = cross_val_score(clf, X, y, cv=10, scoring='accuracy')

print("Mean: {0:.3f}, std: (+/-) {1:.3f} [{2}]".format(scores.mean(), scores.std(), label))Let’s perform the same of voting on our boosting models

# Results

Mean: 0.641, std: (+/-) 0.082 [Ada Boost]

Mean: 0.654, std: (+/-) 0.113 [Grad Boost]

Mean: 0.663, std: (+/-) 0.101 [XG Boost]

Mean: 0.667, std: (+/-) 0.105 [Ensemble]

那么,决策边界是如何看待Boosting算法的呢?有趣的是,无论是boosted 还是bagged 效果都非常相似。

总的来说,似乎我们的boosting集成模型提供了准确性,0.667 这恰好超过了bagging的得分0.658。这并不是说boosting比bagging更好,因为在这些例子中没有任何优化。还应注意,boosting模型的标准偏差较高,这是预期的。

但是,还有一种集成方法可供选择。

Stacking

Stacking是另一个集成模型,在这个模型中,一个新的模型是从两个(或更多)先前模型的组合预测中训练出来的。模型中的预测作为每个序列层的输入,并结合起来形成一组新的预测。这些可以在其他层上使用,或者过程可以在这里停止,得到最终的结果。在下面的例子中,为了简单起见,我只使用一个层。

集成Stacking可以被称为混合,因为所有的数字都被混合以产生预测或分类。

记住,在Stacking算法中添加层和更多的模型并不意味着你会得到一个更好的预测器。机器学习没有免费的午餐。

例如,用Stacking模型我删除SVM从层,并最终从提高精度 .52到 .68。而且,这将在一瞬间变得更加清晰。

Stacking可视化

通常创建Stacking管道会很困难。然而,有一个很棒的ML Ensemble包(http://ml-ensemble.com/)简化了这个过程,让你可以专注于工作和优化模型,而不仅仅是编码。

我采用了[‘Random Forest’, ‘Extra Trees’, ‘KNeighbors’, ‘SVC’, ‘Ridge Classifier’]我们开始使用的vanilla分类器,并将它们组合成所有可能的组合,以测试哪种组合在我们的Stacking模型中表现最佳。

例如['SVC','Ridge Classifier'],['SVC'],['Random Forest','Extra Trees','KNeighbors']等。

一旦完成,我们应该有一些东西可以与我们之前的两个结果进行比较。Mlens确实打包了一个模型选择器,但我想手动显示该过程。

最后,我们将使用逻辑回归作为最终输出层,因为我们仍然希望对住房数据进行分类。Python代码如下:

from itertools import combinations

from sklearn.linear_model import LogisticRegression

lr = LogisticRegression()

names = ['Random Forest', 'Extra Trees', 'KNeighbors', 'SVC', 'Ridge Classifier']

def zip_stacked_classifiers(*args):

to_zip = []

for arg in args:

combined_items = sum([map(list, combinations(arg, i)) for i in range(len(arg) + 1)], [])

combined_items = filter(lambda x: len(x) > 0, combined_items)

to_zip.append(combined_items)

return zip(to_zip[0], to_zip[1])

stacked_clf_list = zip_stacked_classifiers(clf_array, names)

best_combination = [0.00, ""]

for clf in stacked_clf_list:

ensemble = SuperLearner(scorer = accuracy_score,

random_state = seed,

folds = 10)

ensemble.add(clf[0])

ensemble.add_meta(lr)

ensemble.fit(X_train, y_train)

preds = ensemble.predict(X_test)

accuracy = accuracy_score(preds, y_test)

if accuracy > best_combination[0]:

best_combination[0] = accuracy

best_combination[1] = clf[1]

print("Accuracy score: {:.3f} {}").format(accuracy, clf[1])

print("\nBest stacking model is {} with accuracy of: {:.3f}").format(best_combination[1], best_combination[0])

# Output

Accuracy score: 0.674 ['Random Forest']

Accuracy score: 0.663 ['Extra Trees']

Accuracy score: 0.547 ['KNeighbors']

Accuracy score: 0.481 ['SVC']

...

Best stacking model is ['Extra Trees', 'KNeighbors', 'SVC'] with accuracy of: 0.691

看起来我们已经击败了bagging 和boosting模型,得分为 .691。

虽然这个例子只有一层,但mlens我们能够很容易地堆叠越来越多的层。

此外,您还可以对每个模型的参数空间执行伪网格搜索,使用该Evaluator包查找您在堆栈中使用的每个模型的最佳值。

最后

即使 .691是一个相当弱的分类器,我希望通过集成建模和投票的每个阶段的过程是有帮助的。与大多数数据科学一样,大部分工作将用于测试和调整超参数,以及用于改进模型的特征工程。

相关推荐

如何用 coco 数据集训练 Detectron2 模型?

随着最新的Pythorc1.3版本的发布,下一代完全重写了它以前的目标检测框架,新的目标检测框架被称为Detectron2。本教程将通过使用自定义coco数据集训练实例分割模型,帮助你开始使...

CICD联动阿里云容器服务Kubernetes实践之Bamboo篇

本文档以构建一个Java软件项目并部署到阿里云容器服务的Kubernetes集群为例说明如何使用Bamboo在阿里云Kubernetes服务上运行RemoteAgents并在agents上...

Open3D-ML点云语义分割实验【RandLA-Net】

作为点云Open3D-ML实验的一部分,我撰写了文章解释如何使用Tensorflow和PyTorch支持安装此库。为了测试安装,我解释了如何运行一个简单的Python脚本来可视化名为...

清理系统不用第三方工具(系统自带清理软件效果好不?)

清理优化系统一定要借助于优化工具吗?其实,手动优化系统也没有那么神秘,掌握了方法和技巧,系统清理也是一件简单和随心的事。一方面要为每一个可能产生累赘的文件找到清理的方法,另一方面要寻找能够提高工作效率...

【信创】联想开先终端开机不显示grub界面的修改方法

原文链接:【信创】联想开先终端开机不显示grub界面的修改方法...

如意玲珑成熟度再提升,三大发行版支持教程来啦!

前期,我们已分别发布如意玲珑在deepinV23与UOSV20、openEuler24.03发行版的操作指南,本文,我们将为大家详细介绍Ubuntu24.04、Debian12、op...

118种常见的多媒体文件格式(英文简写)

MP4[?mpi?f??]-MPEG-4Part14(MPEG-4第14部分)AVI[e?vi??a?]-AudioVideoInterleave(音视频交错)MOV[m...

密码丢了急上火?码住7种console密码紧急恢复方式!

身为攻城狮的你,...

CSGO丨CS2的cfg指令代码分享(csgo自己的cfg在哪里?config文件位置在哪?)

?...

使用open SSL生成局域网IP地址证书

某些特殊情况下,用户内网访问多可文档管理系统时需要启用SSL传输加密功能,但只有IP,没有域名和证书。这种情况下多可提供了一种免费可行的方式,通过openSSL生成免费证书。此方法生成证书浏览器会提示...

Python中加载配置文件(python怎么加载程序包)

我们在做开发的时候经常要使用配置文件,那么配置文件的加载就需要我们提前考虑,再不使用任何框架的情况下,我们通常会有两种解决办法:完整加载将所有配置信息一次性写入单一配置文件.部分加载将常用配置信息写...

python开发项目,不得不了解的.cfg配置文件

安装软件时,经常会见到后缀为.cfg、.ini的文件,一般我们不用管,只要不删就行。因为这些是程序安装、运行时需要用到的配置文件。但对开发者来说,这种文件是怎么回事就必须搞清了。本文从.cfg文件的创...

瑞芯微RK3568鸿蒙开发板OpenHarmony系统修改cfg文件权限方法

本文适用OpenHarmony开源鸿蒙系统,本次使用的是开源鸿蒙主板,搭载瑞芯微RK3568芯片。深圳触觉智能专注研发生产OpenHarmony开源鸿蒙硬件,包括核心板、开发板、嵌入式主板,工控整机等...

Python9:图像风格迁移-使用阿里的接口

先不多说,直接上结果图。#!/usr/bin/envpython#coding=utf-8importosfromaliyunsdkcore.clientimportAcsClient...

Python带你打造个性化的图片文字识别

我们的目标:从CSV文件读取用户的文件信息,并将文件名称修改为姓名格式的中文名称,进行规范资料整理,从而实现快速对多个文件进行重命名。最终效果:将原来无规律的文件名重命名为以姓名为名称的文件。技术点:...

取消回复欢迎 发表评论:

请填写验证码