Machine-Learning-Mastery-集成学习教程-四-

101 阅读1小时+

Machine Learning Mastery 集成学习教程(四)

原文:Machine Learning Mastery

协议:CC BY-NC-SA 4.0

如何在 Python 中开发特征选择子空间集成

原文:machinelearningmastery.com/feature-sel…

最后更新于 2021 年 4 月 27 日

随机子空间集成由适合训练数据集中不同随机选择的输入特征组(列)的相同模型组成。

在训练数据集中选择特征组的方法有很多,而特征选择是专门为此目的设计的一类流行的数据准备技术。相同特征选择方法和不同特征选择方法的不同配置所选择的特征完全可以作为集成学习的基础。

在本教程中,您将发现如何使用 Python 开发特征选择子空间集成

完成本教程后,您将知道:

  • 特征选择为选择输入特征组提供了随机子空间的替代方案。
  • 如何开发和评估由单个特征选择技术选择的特征组成的集成?
  • 如何开发和评估由多种不同特征选择技术选择的特征组成的集成。

用我的新书Python 集成学习算法启动你的项目,包括分步教程和所有示例的 Python 源代码文件。

我们开始吧。

How to Develop a Feature Selection Subspace Ensemble in Python

如何在 Python 中开发特征选择子空间集成。新西兰,保留部分权利。

教程概述

本教程分为三个部分;它们是:

  1. 特征选择子空间集成
  2. 单特征选择方法集成
    1. 方差分析 f 统计总体
    2. 互信息集成
    3. 递归特征选择集成
  3. 组合特征选择集成
    1. 具有固定数量特征的集合
    2. 具有连续数量特征的集合

特征选择子空间集成

随机子空间方法或随机子空间集成是一种集成学习方法,它在训练数据集中随机选择的不同列组上拟合模型。

用于训练集合中每个模型的列的选择的差异导致模型及其预测的多样性。每个模型都表现良好,尽管每个模型的表现不同,犯的错误也不同。

训练数据通常由一组特征描述。不同的特征子集,或称为子空间,提供不同的数据视图。因此,从不同子空间训练的个体学习器通常是不同的。

—第 116 页,集合方法,2012。

随机子空间方法通常与决策树一起使用,然后使用简单的统计信息组合每棵树做出的预测,例如计算用于分类的模式类别标签或用于回归的平均预测。

特征选择是一种数据准备技术,它试图选择数据集中与目标变量最相关的列子集。流行的方法包括使用统计方法,如互信息,评估特征子集上的模型,并选择产生最佳表现模型的子集,称为递归特征消除,简称 RFE。

每种特征选择方法对于哪些特征与目标变量最相关会有不同的想法或明智的猜测。此外,可以定制特征选择方法,从 1 到数据集中的列总数中选择特定数量的特征,这是一个可以作为模型选择的一部分进行调整的超参数。

每组选择的特征可以被认为是输入特征空间的子集,很像随机子空间集合,尽管是使用度量而不是随机选择的。我们可以使用由特征选择方法选择的特征作为一种集成模型。

可能有许多方法可以实现这一点,但可能有两种自然的方法包括:

  • 一种方法:为数据集中从 1 到列数的每个特征生成一个特征子空间,在每个特征子空间上拟合一个模型,并组合它们的预测。
  • 多种方法:使用多种不同的特征选择方法生成特征子空间,在每种方法上拟合一个模型,并组合它们的预测。

由于没有更好的名字,我们可以称之为“特征选择子空间集成

我们将在本教程中探讨这个想法。

让我们定义一个测试问题作为这种探索的基础,并建立一个表现基线,看看它是否比单个模型有好处。

首先,我们可以使用 make_classification()函数创建一个包含 1000 个示例和 20 个输入特征的合成二进制分类问题,其中 5 个是冗余的。

下面列出了完整的示例。

# synthetic classification dataset
from sklearn.datasets import make_classification
# define dataset
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=5)
# summarize the dataset
print(X.shape, y.shape)

运行该示例将创建数据集并总结输入和输出组件的形状。

(1000, 20) (1000,)

接下来,我们可以建立一个表现基线。我们将为数据集开发一个决策树,并使用三次重复和 10 次重复的重复分层 k-fold 交叉验证对其进行评估。

结果将报告为所有重复和折叠的分类准确度的平均值和标准偏差。

下面列出了完整的示例。

# evaluate a decision tree on the classification dataset
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.tree import DecisionTreeClassifier
# define dataset
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=5)
# define the random subspace ensemble model
model = DecisionTreeClassifier()
# define the evaluation method
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate the model on the dataset
n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
# report performance
print('Mean Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))

运行该示例会报告平均和标准偏差分类准确率。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到单个决策树模型实现了大约 79.4%的分类准确率。我们可以将此作为表现的基准,看看我们的功能选择集成是否能够实现更好的表现。

Mean Accuracy: 0.794 (0.046)

接下来,让我们探索使用不同的特征选择方法作为集成的基础。

单特征选择方法集成

在本节中,我们将探索如何从单个特征选择方法选择的特征中创建一个集合。

对于给定的特征选择方法,我们将对不同数量的所选特征重复应用它,以创建多个特征子空间。然后,我们将在每一个模型上训练一个模型,在这个例子中是一个决策树,并组合预测。

有许多方法可以组合预测,但为了简单起见,我们将使用投票集合,该集合可以配置为使用硬或软投票进行分类,或者使用平均进行回归。为了保持例子简单,我们将集中在分类和使用硬投票,因为决策树不能预测校准概率,使得软投票不太合适。

要了解有关投票集成的更多信息,请参阅教程:

投票集成中的每个模型将是管道,其中第一步是特征选择方法,被配置为选择特定数量的特征,随后是决策树分类器模型。

我们将为输入数据集中从 1 到列数的每个列数创建一个特征选择子空间。为了简单起见,这是任意选择的,您可能希望在集合中尝试不同数量的特征,例如奇数个特征,或者更复杂的方法。

因此,我们可以定义一个名为 get_ensemble() 的辅助函数,为给定数量的输入特征创建一个具有基于特征选择的成员的投票集成。然后,我们可以使用这个函数作为模板来探索使用不同的特征选择方法。

# get a voting ensemble of models
def get_ensemble(n_features):
	# define the base models
	models = list()
	# enumerate the features in the training dataset
	for i in range(1, n_features+1):
		# create the feature selection transform
		fs = ...
		# create the model
		model = DecisionTreeClassifier()
		# create the pipeline
		pipe = Pipeline([('fs',fs), ('m', model)])
		# add as a tuple to the list of models for voting
		models.append((str(i),pipe))
	# define the voting ensemble
	ensemble = VotingClassifier(estimators=models, voting='hard')
	return ensemble

假设我们正在使用类别数据集,我们将探索三种不同的特征选择方法:

  • 方差分析 f 统计量。
  • 相互信息。
  • 递归特征选择。

让我们仔细看看每一个。

方差分析 f 统计总体

ANOVA 是“方差分析”的缩写,是一种参数统计假设检验,用于确定两个或多个数据样本(通常是三个或更多)的平均值是否来自同一分布。

f 统计或 f 检验是一类统计检验,用于计算方差值之间的比率,如两个不同样本的方差或通过统计检验解释和解释的方差,如方差分析。方差分析方法是一种 f 统计,这里称为方差分析 f 检验

Sklearn 机器库提供了 f_classif()函数中方差分析 F-检验的实现。该功能可用于特征选择策略,例如通过选择最相关的特征(最大值)选择最相关的 k

# get a voting ensemble of models
def get_ensemble(n_features):
	# define the base models
	models = list()
	# enumerate the features in the training dataset
	for i in range(1, n_features+1):
		# create the feature selection transform
		fs = SelectKBest(score_func=f_classif, k=i)
		# create the model
		model = DecisionTreeClassifier()
		# create the pipeline
		pipe = Pipeline([('fs',fs), ('m', model)])
		# add as a tuple to the list of models for voting
		models.append((str(i),pipe))
	# define the voting ensemble
	ensemble = VotingClassifier(estimators=models, voting='hard')
	return ensemble

将这些联系在一起,下面的例子评估了一个由模型组成的投票集合,这些模型适合于由方差分析统计选择的特征子空间。

# example of an ensemble created from features selected with the anova f-statistic
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_classif
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import VotingClassifier
from sklearn.pipeline import Pipeline
from matplotlib import pyplot

# get a voting ensemble of models
def get_ensemble(n_features):
	# define the base models
	models = list()
	# enumerate the features in the training dataset
	for i in range(1, n_features+1):
		# create the feature selection transform
		fs = SelectKBest(score_func=f_classif, k=i)
		# create the model
		model = DecisionTreeClassifier()
		# create the pipeline
		pipe = Pipeline([('fs',fs), ('m', model)])
		# add as a tuple to the list of models for voting
		models.append((str(i),pipe))
	# define the voting ensemble
	ensemble = VotingClassifier(estimators=models, voting='hard')
	return ensemble

# define dataset
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=5)
# get the ensemble model
ensemble = get_ensemble(X.shape[1])
# define the evaluation method
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate the model on the dataset
n_scores = cross_val_score(ensemble, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
# report performance
print('Mean Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))

运行该示例会报告平均和标准偏差分类准确率。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到单个模型的表现有所提升,使用基于方差分析统计选择的特征的模型集合,该模型的准确率达到了约 79.4%至约 83.2%。

Mean Accuracy: 0.832 (0.043)

接下来,让我们探索使用相互信息。

互信息集成

互信息来自信息论领域的是信息增益(通常用于决策树的构建)对特征选择的应用。

计算两个变量之间的互信息,并在已知另一个变量的值的情况下,测量一个变量不确定性的减少。当考虑两个离散(分类或序数)变量的分布时,例如分类输入和分类输出数据,这很简单。然而,它可以适用于数字输入和分类输出。

Sklearn 机器学习库通过 mutual_info_classif()函数为特征选择提供了数字输入和分类输出变量的互信息实现。和 f_classif() 一样,可以在 SelectKBest 特征选择策略(和其他策略)中使用。

# get a voting ensemble of models
def get_ensemble(n_features):
	# define the base models
	models = list()
	# enumerate the features in the training dataset
	for i in range(1, n_features+1):
		# create the feature selection transform
		fs = SelectKBest(score_func=mutual_info_classif, k=i)
		# create the model
		model = DecisionTreeClassifier()
		# create the pipeline
		pipe = Pipeline([('fs',fs), ('m', model)])
		# add as a tuple to the list of models for voting
		models.append((str(i),pipe))
	# define the voting ensemble
	ensemble = VotingClassifier(estimators=models, voting='hard')
	return ensemble

将这些联系在一起,下面的例子评估了一个由模型组成的投票集合,这些模型适合由互信息选择的特征子空间。

# example of an ensemble created from features selected with mutual information
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import mutual_info_classif
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import VotingClassifier
from sklearn.pipeline import Pipeline
from matplotlib import pyplot

# get a voting ensemble of models
def get_ensemble(n_features):
	# define the base models
	models = list()
	# enumerate the features in the training dataset
	for i in range(1, n_features+1):
		# create the feature selection transform
		fs = SelectKBest(score_func=mutual_info_classif, k=i)
		# create the model
		model = DecisionTreeClassifier()
		# create the pipeline
		pipe = Pipeline([('fs',fs), ('m', model)])
		# add as a tuple to the list of models for voting
		models.append((str(i),pipe))
	# define the voting ensemble
	ensemble = VotingClassifier(estimators=models, voting='hard')
	return ensemble

# define dataset
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=5)
# get the ensemble model
ensemble = get_ensemble(X.shape[1])
# define the evaluation method
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate the model on the dataset
n_scores = cross_val_score(ensemble, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
# report performance
print('Mean Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))

运行该示例会报告平均和标准偏差分类准确率。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到表现比使用单一模型有所提升,尽管比选择的特征子空间略少,方差分析的平均准确率约为 82.7%。

Mean Accuracy: 0.827 (0.048)

接下来,让我们探索使用 RFE 选择的子空间。

递归特征选择集成

递归特征消除(简称 RFE)的工作原理是,从训练数据集中的所有特征开始搜索特征子集,并成功移除特征,直到保留所需数量。

这是通过拟合模型核心中使用的给定机器学习算法、按重要性排列特征、丢弃最不重要的特征以及重新拟合模型来实现的。重复此过程,直到保留指定数量的特征。

有关 RFE 的更多信息,请参见教程:

RFE 方法可通过 Sklearn 中的 RFE 类获得,并可直接用于特征选择。不需要和选择测试类结合。

# get a voting ensemble of models
def get_ensemble(n_features):
	# define the base models
	models = list()
	# enumerate the features in the training dataset
	for i in range(1, n_features+1):
		# create the feature selection transform
		fs = RFE(estimator=DecisionTreeClassifier(), n_features_to_select=i)
		# create the model
		model = DecisionTreeClassifier()
		# create the pipeline
		pipe = Pipeline([('fs',fs), ('m', model)])
		# add as a tuple to the list of models for voting
		models.append((str(i),pipe))
	# define the voting ensemble
	ensemble = VotingClassifier(estimators=models, voting='hard')
	return ensemble

将这些联系在一起,下面的例子评估了由适合 RFE 选择的特征子空间的模型组成的投票集合。

# example of an ensemble created from features selected with RFE
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.feature_selection import RFE
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import VotingClassifier
from sklearn.pipeline import Pipeline
from matplotlib import pyplot

# get a voting ensemble of models
def get_ensemble(n_features):
	# define the base models
	models = list()
	# enumerate the features in the training dataset
	for i in range(1, n_features+1):
		# create the feature selection transform
		fs = RFE(estimator=DecisionTreeClassifier(), n_features_to_select=i)
		# create the model
		model = DecisionTreeClassifier()
		# create the pipeline
		pipe = Pipeline([('fs',fs), ('m', model)])
		# add as a tuple to the list of models for voting
		models.append((str(i),pipe))
	# define the voting ensemble
	ensemble = VotingClassifier(estimators=models, voting='hard')
	return ensemble

# define dataset
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=5)
# get the ensemble model
ensemble = get_ensemble(X.shape[1])
# define the evaluation method
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate the model on the dataset
n_scores = cross_val_score(ensemble, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
# report performance
print('Mean Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))

运行该示例会报告平均和标准偏差分类准确率。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到平均准确率与互信息特征选择相似,得分约为 82.3%。

Mean Accuracy: 0.823 (0.045)

这是一个好的开始,看看使用由更少成员组成的集成(例如,每隔一秒、三分之一或五分之一数量的选定特征)是否可以获得更好的结果可能会很有趣。

接下来,让我们看看是否可以通过组合适合不同特征选择方法选择的特征子空间的模型来提高结果。

组合特征选择集成

在前一节中,我们看到,通过使用单个特征选择方法作为数据集集成预测的基础,我们可以提升单个模型的表现。

我们预计,许多集成成员之间的预测是相关的。这可以通过使用不同数量的所选输入特征作为集合的基础来解决,而不是从 1 到列数的连续数量的特征。

引入多样性的另一种方法是使用不同的特征选择方法来选择特征子空间。

我们将探讨这种方法的两个版本。对于第一种方法,我们将从每个方法中选择相同数量的特征,对于第二种方法,我们将从 1 到多个方法的列数中选择连续数量的特征。

具有固定数量特征的集合

在本节中,我们将首次尝试使用由多种特征选择技术选择的特征来设计一个集合。

我们将从数据集中选择任意数量的特征,然后使用三种特征选择方法中的每一种来选择特征子空间,拟合每一种的模型,并将它们用作投票集成的基础。

下面的 get_ensemble() 函数实现了这一点,将每个方法要选择的指定数量的特征作为参数。希望通过每种方法选择的特征足够不同,足够熟练,以产生有效的集成。

# get a voting ensemble of models
def get_ensemble(n_features):
	# define the base models
	models = list()
	# anova
	fs = SelectKBest(score_func=f_classif, k=n_features)
	anova = Pipeline([('fs', fs), ('m', DecisionTreeClassifier())])
	models.append(('anova', anova))
	# mutual information
	fs = SelectKBest(score_func=mutual_info_classif, k=n_features)
	mutinfo = Pipeline([('fs', fs), ('m', DecisionTreeClassifier())])
	models.append(('mutinfo', mutinfo))
	# rfe
	fs = RFE(estimator=DecisionTreeClassifier(), n_features_to_select=n_features)
	rfe = Pipeline([('fs', fs), ('m', DecisionTreeClassifier())])
	models.append(('rfe', rfe))
	# define the voting ensemble
	ensemble = VotingClassifier(estimators=models, voting='hard')
	return ensemble

将这些联系在一起,下面的例子评估了使用不同特征选择方法选择的固定数量的特征的集合。

# ensemble of a fixed number features selected by different feature selection methods
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.feature_selection import RFE
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import mutual_info_classif
from sklearn.feature_selection import f_classif
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import VotingClassifier
from sklearn.pipeline import Pipeline
from matplotlib import pyplot

# get a voting ensemble of models
def get_ensemble(n_features):
	# define the base models
	models = list()
	# anova
	fs = SelectKBest(score_func=f_classif, k=n_features)
	anova = Pipeline([('fs', fs), ('m', DecisionTreeClassifier())])
	models.append(('anova', anova))
	# mutual information
	fs = SelectKBest(score_func=mutual_info_classif, k=n_features)
	mutinfo = Pipeline([('fs', fs), ('m', DecisionTreeClassifier())])
	models.append(('mutinfo', mutinfo))
	# rfe
	fs = RFE(estimator=DecisionTreeClassifier(), n_features_to_select=n_features)
	rfe = Pipeline([('fs', fs), ('m', DecisionTreeClassifier())])
	models.append(('rfe', rfe))
	# define the voting ensemble
	ensemble = VotingClassifier(estimators=models, voting='hard')
	return ensemble

# define dataset
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=1)
# get the ensemble model
ensemble = get_ensemble(15)
# define the evaluation method
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate the model on the dataset
n_scores = cross_val_score(ensemble, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
# report performance
print('Mean Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))

运行该示例会报告平均和标准偏差分类准确率。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到表现相对于上一节中考虑的技术有适度的提升,导致平均分类准确率约为 83.9%。

Mean Accuracy: 0.839 (0.044)

更公平的比较可能是将这个结果与构成整体的每个单独模型进行比较。

更新后的示例恰好执行了这种比较。

# comparison of ensemble of a fixed number features to single models fit on each set of features
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.feature_selection import RFE
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import mutual_info_classif
from sklearn.feature_selection import f_classif
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import VotingClassifier
from sklearn.pipeline import Pipeline
from matplotlib import pyplot

# get a voting ensemble of models
def get_ensemble(n_features):
	# define the base models
	models, names = list(), list()
	# anova
	fs = SelectKBest(score_func=f_classif, k=n_features)
	anova = Pipeline([('fs', fs), ('m', DecisionTreeClassifier())])
	models.append(('anova', anova))
	names.append('anova')
	# mutual information
	fs = SelectKBest(score_func=mutual_info_classif, k=n_features)
	mutinfo = Pipeline([('fs', fs), ('m', DecisionTreeClassifier())])
	models.append(('mutinfo', mutinfo))
	names.append('mutinfo')
	# rfe
	fs = RFE(estimator=DecisionTreeClassifier(), n_features_to_select=n_features)
	rfe = Pipeline([('fs', fs), ('m', DecisionTreeClassifier())])
	models.append(('rfe', rfe))
	names.append('rfe')
	# define the voting ensemble
	ensemble = VotingClassifier(estimators=models, voting='hard')
	names.append('ensemble')
	return names, [anova, mutinfo, rfe, ensemble]

# define dataset
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=1)
# get the ensemble model
names, models = get_ensemble(15)
# evaluate each model
results = list()
for model,name in zip(models,names):
	# define the evaluation method
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	# evaluate the model on the dataset
	n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	# report performance
	print('>%s: %.3f (%.3f)' % (name, mean(n_scores), std(n_scores)))
	results.append(n_scores)
# plot the results for comparison
pyplot.boxplot(results, labels=names)
pyplot.show()

运行该示例会报告每个单个模型在选定特征上的平均表现,并以组合所有三个模型的集合的表现结束。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,结果表明,如我们所希望的那样,适合所选特征的模型集合比集合中的任何单个模型表现得更好。

>anova: 0.811 (0.048)
>mutinfo: 0.807 (0.041)
>rfe: 0.825 (0.043)
>ensemble: 0.837 (0.040)

创建一个图形来显示每组结果的方框图和触须图,允许直接比较分布准确度分数。

我们可以看到,集合的分布倾斜得更高,并且具有更大的中值分类准确率(橙色线),直观地证实了这一发现。

Box and Whisker Plots of Accuracy of Singles Model Fit On Selected Features vs. Ensemble

单个模型拟合选定特征与整体的准确度的方框图和触须图

接下来,让我们探索为每个特征选择方法添加多个成员。

具有连续数量特征的集合

我们可以把上一节的实验和上面的实验结合起来。

具体来说,我们可以使用每个特征选择方法选择多个特征子空间,在每个子空间上拟合一个模型,并将所有模型添加到单个集成中。

在这种情况下,我们将选择子空间,就像我们在上一节中从 1 到数据集中的列数一样,尽管在这种情况下,用每个特征选择方法重复这个过程。

# get a voting ensemble of models
def get_ensemble(n_features_start, n_features_end):
	# define the base models
	models = list()
	for i in range(n_features_start, n_features_end+1):
		# anova
		fs = SelectKBest(score_func=f_classif, k=i)
		anova = Pipeline([('fs', fs), ('m', DecisionTreeClassifier())])
		models.append(('anova'+str(i), anova))
		# mutual information
		fs = SelectKBest(score_func=mutual_info_classif, k=i)
		mutinfo = Pipeline([('fs', fs), ('m', DecisionTreeClassifier())])
		models.append(('mutinfo'+str(i), mutinfo))
		# rfe
		fs = RFE(estimator=DecisionTreeClassifier(), n_features_to_select=i)
		rfe = Pipeline([('fs', fs), ('m', DecisionTreeClassifier())])
		models.append(('rfe'+str(i), rfe))
	# define the voting ensemble
	ensemble = VotingClassifier(estimators=models, voting='hard')
	return ensemble

希望通过特征选择方法选择的特征的多样性导致集成表现的进一步提升。

将这些联系在一起,完整的示例如下所示。

# ensemble of many subsets of features selected by multiple feature selection methods
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.feature_selection import RFE
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import mutual_info_classif
from sklearn.feature_selection import f_classif
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import VotingClassifier
from sklearn.pipeline import Pipeline
from matplotlib import pyplot

# get a voting ensemble of models
def get_ensemble(n_features_start, n_features_end):
	# define the base models
	models = list()
	for i in range(n_features_start, n_features_end+1):
		# anova
		fs = SelectKBest(score_func=f_classif, k=i)
		anova = Pipeline([('fs', fs), ('m', DecisionTreeClassifier())])
		models.append(('anova'+str(i), anova))
		# mutual information
		fs = SelectKBest(score_func=mutual_info_classif, k=i)
		mutinfo = Pipeline([('fs', fs), ('m', DecisionTreeClassifier())])
		models.append(('mutinfo'+str(i), mutinfo))
		# rfe
		fs = RFE(estimator=DecisionTreeClassifier(), n_features_to_select=i)
		rfe = Pipeline([('fs', fs), ('m', DecisionTreeClassifier())])
		models.append(('rfe'+str(i), rfe))
	# define the voting ensemble
	ensemble = VotingClassifier(estimators=models, voting='hard')
	return ensemble

# define dataset
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=1)
# get the ensemble model
ensemble = get_ensemble(1, 20)
# define the evaluation method
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate the model on the dataset
n_scores = cross_val_score(ensemble, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
# report performance
print('Mean Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))

运行该示例会报告集合的均值和标准差分类准确率。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到表现的进一步提升,正如我们所希望的那样,组合集成导致平均分类准确率约为 86.0%。

Mean Accuracy: 0.860 (0.036)

使用特征选择来选择输入特征的子空间可以为选择随机子空间提供一个有趣的替代或者补充。

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

教程

蜜蜂

文章

摘要

在本教程中,您发现了如何使用 Python 开发特征选择子空间集成。

具体来说,您了解到:

  • 特征选择为选择输入特征组提供了随机子空间的替代方案。
  • 如何开发和评估由单个特征选择技术选择的特征组成的集成?
  • 如何开发和评估由多种不同特征选择技术选择的特征组成的集成。

你有什么问题吗? 在下面的评论中提问,我会尽力回答。

如何在 Python 中开发梯度提升机集成

原文:machinelearningmastery.com/gradient-bo…

最后更新于 2021 年 4 月 27 日

梯度提升机是一个强大的集成机器学习算法,使用决策树。

增强是一种通用的集成技术,包括向集成中顺序添加模型,其中后续模型校正先前模型的表现。AdaBoost 是第一个兑现 boosting 承诺的算法。

梯度提升是 AdaBoosting 的推广,提高了方法的表现,并引入了自举聚合的思想来进一步改进模型,例如在拟合集成成员时随机采样样本和特征。

梯度提升在广泛的表格数据集上表现良好,即使不是最好的,也是,像 XGBoost 和 LightBoost 这样的算法版本通常在赢得机器学习竞赛中发挥重要作用。

在本教程中,您将发现如何为分类和回归开发梯度提升集成。

完成本教程后,您将知道:

  • 梯度提升集成是由顺序添加到模型中的决策树创建的集成。
  • 如何用 Sklearn 使用梯度提升集成进行分类和回归。
  • 如何探索梯度提升模型超参数对模型表现的影响。

用我的新书Python 集成学习算法启动你的项目,包括分步教程和所有示例的 Python 源代码文件。

我们开始吧。

  • 更新 2020 年 8 月:增加了常见问题部分。添加了网格搜索示例。

How to Develop a Gradient Boosting Machine Ensemble in Python

如何开发 Python 中的梯度提升机集成 图片由 Susanne Nilsson 提供,保留部分权利。

教程概述

本教程分为五个部分;它们是:

  1. 梯度提升算法
  2. 梯度提升科学工具包-学习应用编程接口
    1. 用于分类的梯度提升
    2. 回归的梯度提升
  3. 梯度提升超参数
    1. 探索树的数量
    2. 探索样本数量
    3. 探索功能数量
    4. 探索学习率
    5. 探索树的深度
  4. 网格搜索超参数
  5. 常见问题

梯度提升机算法

梯度提升是指一类集成机器学习算法,可用于分类或回归预测建模问题。

梯度提升也称为梯度树增强、随机梯度提升(扩展)和梯度提升机,简称 GBM。

集成是由决策树模型构建的。树被一次一个地添加到集合中,并且适合于校正由先前模型产生的预测误差。这是一种称为 boosting 的集成机器学习模型。

使用任意可微损失函数和梯度下降优化算法拟合模型。这给这项技术起了一个名字,“梯度提升”,因为随着模型的拟合,损失梯度被最小化,很像一个神经网络。

产生优化[成本]的加权分类器组合的一种方法是通过函数空间中的梯度下降

——函数空间中梯度下降的增强算法,1999。

朴素梯度提升算法是一种贪婪算法,可以快速过度训练数据集。

它可以受益于惩罚算法各个部分的正则化方法,并且通常通过减少过拟合来提高算法的表现。

基本梯度提升有三种类型的增强可以提高表现:

  • 树约束:比如树的深度和集成中使用的树的数量。
  • 加权更新:比如一个学习率,用来限制每棵树对集成的贡献。
  • 随机采样:比如在特征和样本的随机子集上拟合树。

随机采样的使用通常会导致算法名称更改为“随机梯度提升

……在每次迭代中,从完整的训练数据集中随机抽取一个训练数据的子样本(没有替换)。然后使用随机选择的子样本,而不是整个样本,来适应基础学习器。

——随机梯度提升,1999。

梯度提升是一种有效的机器学习算法,并且通常是用于在表格和类似结构化数据集上赢得机器学习竞赛(如 Kaggle)的主要算法或主要算法之一。

有关梯度提升算法的更多信息,请参见教程:

现在我们已经熟悉了梯度提升算法,让我们看看如何在 Python 中拟合 GBM 模型。

梯度提升科学工具包-学习应用编程接口

梯度提升集成可以从零开始实现,尽管对初学者来说很有挑战性。

Sklearn Python 机器学习库为机器学习提供了梯度提升集成的实现。

该算法在现代版本的库中可用。

首先,通过运行以下脚本来确认您使用的是现代版本的库:

# check Sklearn version
import sklearn
print(sklearn.__version__)

运行脚本将打印您的 Sklearn 版本。

您的版本应该相同或更高。如果没有,您必须升级 Sklearn 库的版本。

0.22.1

梯度提升通过梯度提升回归器梯度提升分类器类提供。

这两个模型以相同的方式运行,并采用相同的参数来影响决策树的创建和添加。

随机性用于模型的构建。这意味着算法每次在相同的数据上运行时,都会产生稍微不同的模型。

当使用具有随机学习算法的机器学习算法时,最好通过在多次运行或重复交叉验证中平均它们的表现来评估它们。当拟合最终模型时,可能需要增加树的数量,直到模型的方差在重复评估中减小,或者拟合多个最终模型并对它们的预测进行平均。

让我们看看如何为分类和回归开发一个梯度提升集成。

用于分类的梯度提升

在本节中,我们将研究如何使用梯度提升来解决分类问题。

首先,我们可以使用 make_classification()函数创建一个包含 1000 个示例和 20 个输入特征的合成二进制分类问题。

下面列出了完整的示例。

# test classification dataset
from sklearn.datasets import make_classification
# define dataset
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=7)
# summarize the dataset
print(X.shape, y.shape)

运行该示例将创建数据集并总结输入和输出组件的形状。

(1000, 20) (1000,)

接下来,我们可以在这个数据集上评估一个梯度提升算法。

我们将使用重复的分层 k 折叠交叉验证来评估模型,重复 3 次,折叠 10 次。我们将报告所有重复和折叠的模型准确率的平均值和标准偏差。

# evaluate gradient boosting algorithm for classification
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.ensemble import GradientBoostingClassifier
# define dataset
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=7)
# define the model
model = GradientBoostingClassifier()
# define the evaluation method
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate the model on the dataset
n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
# report performance
print('Mean Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))

运行该示例会报告模型的均值和标准差准确率。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到带有默认超参数的梯度提升集成在这个测试数据集上实现了大约 89.9%的分类准确率。

Mean Accuracy: 0.899 (0.030)

我们也可以使用梯度提升模型作为最终模型,并对分类进行预测。

首先,对所有可用数据进行梯度提升集成,然后调用 predict() 函数对新数据进行预测。

下面的示例在我们的二进制类别数据集上演示了这一点。

# make predictions using gradient boosting for classification
from sklearn.datasets import make_classification
from sklearn.ensemble import GradientBoostingClassifier
# define dataset
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=7)
# define the model
model = GradientBoostingClassifier()
# fit the model on the whole dataset
model.fit(X, y)
# make a single prediction
row = [0.2929949, -4.21223056, -1.288332, -2.17849815, -0.64527665, 2.58097719, 0.28422388, -7.1827928, -1.91211104, 2.73729512, 0.81395695, 3.96973717, -2.66939799, 3.34692332, 4.19791821, 0.99990998, -0.30201875, -4.43170633, -2.82646737, 0.44916808]
yhat = model.predict([row])
# summarize prediction
print('Predicted Class: %d' % yhat[0])

运行该示例使梯度提升集成模型适合整个数据集,然后用于对新的数据行进行预测,就像我们在应用程序中使用该模型时可能做的那样。

Predicted Class: 1

现在我们已经熟悉了使用梯度提升进行分类,让我们看看回归的应用编程接口。

回归的梯度提升

在本节中,我们将研究使用梯度提升来解决回归问题。

首先,我们可以使用make _ revolution()函数创建一个包含 1000 个示例和 20 个输入特征的合成回归问题。

下面列出了完整的示例。

# test regression dataset
from sklearn.datasets import make_regression
# define dataset
X, y = make_regression(n_samples=1000, n_features=20, n_informative=15, noise=0.1, random_state=7)
# summarize the dataset
print(X.shape, y.shape)

运行该示例将创建数据集并总结输入和输出组件的形状。

(1000, 20) (1000,)

接下来,我们可以在这个数据集上评估一个梯度提升算法。

正如我们在上一节中所做的,我们将使用重复的 k-fold 交叉验证来评估模型,重复 3 次,重复 10 次。我们将报告所有重复和折叠模型的平均绝对误差(MAE)。Sklearn 库使 MAE 为负,因此它被最大化而不是最小化。这意味着负 MAE 越大越好,完美模型的 MAE 为 0。

下面列出了完整的示例。

# evaluate gradient boosting ensemble for regression
from numpy import mean
from numpy import std
from sklearn.datasets import make_regression
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedKFold
from sklearn.ensemble import GradientBoostingRegressor
# define dataset
X, y = make_regression(n_samples=1000, n_features=20, n_informative=15, noise=0.1, random_state=7)
# define the model
model = GradientBoostingRegressor()
# define the evaluation procedure
cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate the model
n_scores = cross_val_score(model, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1)
# report performance
print('MAE: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))

运行该示例会报告模型的均值和标准差准确率。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到带有默认超参数的梯度提升集成实现了大约 62 的 MAE。

MAE: -62.475 (3.254)

我们也可以使用梯度提升模型作为最终模型,并对回归进行预测。

首先,梯度提升集合适合所有可用数据,然后可以调用 predict()函数对新数据进行预测。

下面的例子在我们的回归数据集上演示了这一点。

# gradient boosting ensemble for making predictions for regression
from sklearn.datasets import make_regression
from sklearn.ensemble import GradientBoostingRegressor
# define dataset
X, y = make_regression(n_samples=1000, n_features=20, n_informative=15, noise=0.1, random_state=7)
# define the model
model = GradientBoostingRegressor()
# fit the model on the whole dataset
model.fit(X, y)
# make a single prediction
row = [0.20543991, -0.97049844, -0.81403429, -0.23842689, -0.60704084, -0.48541492, 0.53113006, 2.01834338, -0.90745243, -1.85859731, -1.02334791, -0.6877744, 0.60984819, -0.70630121, -1.29161497, 1.32385441, 1.42150747, 1.26567231, 2.56569098, -0.11154792]
yhat = model.predict([row])
# summarize prediction
print('Prediction: %d' % yhat[0])

运行该示例使梯度提升集成模型适合整个数据集,然后用于对新的数据行进行预测,就像我们在应用程序中使用该模型时可能做的那样。

Prediction: 37

现在我们已经熟悉了使用 Sklearn API 来评估和使用 Gradient Boosting 集成,接下来让我们看看如何配置模型。

梯度提升超参数

在本节中,我们将仔细研究一些您应该考虑为梯度提升集成进行调整的超参数,以及它们对模型表现的影响。

可能有四个关键的超参数对模型表现有最大的影响,它们是集成中的模型数量、学习率、通过用于训练每个模型的数据样本的大小或用于树分裂的特征来控制的模型方差,最后是决策树的深度。

在本节中,我们将仔细研究这些超参数中的每一个单独的影响,尽管它们都相互作用,并且应该一起或成对调整,例如学习率与集成大小,以及样本大小/特征数量与树深度。

有关调整梯度提升算法的超参数的更多信息,请参见教程:

探索树的数量

梯度提升集成算法的一个重要超参数是集成中使用的决策树数量。

回想一下,决策树被顺序地添加到模型中,以努力纠正和改进先前的树所做的预测。因此,更多的树往往更好。树的数量也必须与学习率相平衡,例如,更多的树可能需要更小的学习率,更少的树可能需要更大的学习率。

树的数量可以通过“n _ estimates”参数设置,默认为 100。

下面的示例探讨了值在 10 到 5,000 之间的树的数量的影响。

# explore gradient boosting number of trees effect on performance
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.ensemble import GradientBoostingClassifier
from matplotlib import pyplot

# get the dataset
def get_dataset():
	X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=7)
	return X, y

# get a list of models to evaluate
def get_models():
	models = dict()
	# define number of trees to consider
	n_trees = [10, 50, 100, 500, 1000, 5000]
	for n in n_trees:
		models[str(n)] = GradientBoostingClassifier(n_estimators=n)
	return models

# evaluate a given model using cross-validation
def evaluate_model(model, X, y):
	# define the evaluation procedure
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	# evaluate the model and collect the results
	scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	return scores

# define dataset
X, y = get_dataset()
# get the models to evaluate
models = get_models()
# evaluate the models and store results
results, names = list(), list()
for name, model in models.items():
	# evaluate the model
	scores = evaluate_model(model, X, y)
	# store the results
	results.append(scores)
	names.append(name)
	# summarize the performance along the way
	print('>%s %.3f (%.3f)' % (name, mean(scores), std(scores)))
# plot model performance for comparison
pyplot.boxplot(results, labels=names, showmeans=True)
pyplot.show()

运行该示例首先报告每个配置数量的决策树的平均准确性。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到该数据集上的表现有所提高,直到大约 500 棵树,之后表现似乎趋于平稳。与 AdaBoost 不同,在这种情况下,随着树的数量增加,梯度提升似乎不会过度。

>10 0.830 (0.037)
>50 0.880 (0.033)
>100 0.899 (0.030)
>500 0.919 (0.025)
>1000 0.919 (0.025)
>5000 0.918 (0.026)

为每个配置数量的树的准确度分数的分布创建一个方框和须图。

我们可以看到模型表现和集合规模增加的总体趋势。

Box Plot of Gradient Boosting Ensemble Size vs. Classification Accuracy

梯度提升集合大小与分类准确率的箱线图

探索样本数量

用于拟合每棵树的样本数量可以变化。这意味着每棵树都适合随机选择的训练数据集子集。

使用更少的样本会为每棵树引入更多的方差,尽管这可以提高模型的整体表现。

用于拟合每棵树的样本数量由“子样本参数指定,并且可以设置为训练数据集大小的一小部分。默认情况下,它被设置为 1.0 以使用整个训练数据集。

下面的示例演示了样本大小对模型表现的影响。

# explore gradient boosting ensemble number of samples effect on performance
from numpy import mean
from numpy import std
from numpy import arange
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.ensemble import GradientBoostingClassifier
from matplotlib import pyplot

# get the dataset
def get_dataset():
	X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=7)
	return X, y

# get a list of models to evaluate
def get_models():
	models = dict()
	# explore sample ratio from 10% to 100% in 10% increments
	for i in arange(0.1, 1.1, 0.1):
		key = '%.1f' % i
		models[key] = GradientBoostingClassifier(subsample=i)
	return models

# evaluate a given model using cross-validation
def evaluate_model(model, X, y):
	# define the evaluation procedure
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	# evaluate the model and collect the results
	scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	return scores

# define dataset
X, y = get_dataset()
# get the models to evaluate
models = get_models()
# evaluate the models and store results
results, names = list(), list()
for name, model in models.items():
	# evaluate the model
	scores = evaluate_model(model, X, y)
	# store the results
	results.append(scores)
	names.append(name)
	# summarize the performance along the way
	print('>%s %.3f (%.3f)' % (name, mean(scores), std(scores)))
# plot model performance for comparison
pyplot.boxplot(results, labels=names, showmeans=True)
pyplot.show()

运行示例首先报告每个配置样本大小的平均准确度。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到平均表现对于大约是训练数据集一半大小的样本来说可能是最好的,例如 0.4 或更高。

>0.1 0.872 (0.033)
>0.2 0.897 (0.032)
>0.3 0.904 (0.029)
>0.4 0.907 (0.032)
>0.5 0.906 (0.027)
>0.6 0.908 (0.030)
>0.7 0.902 (0.032)
>0.8 0.901 (0.031)
>0.9 0.904 (0.031)
>1.0 0.899 (0.030)

为每个配置数量的树的准确度分数的分布创建一个方框和须图。

我们可以看到提高模型表现的总体趋势,可能在 0.4 左右达到峰值,并保持一定水平。

Box Plot of Gradient Boosting Ensemble Sample Size vs. Classification Accuracy

梯度提升集合样本量与分类准确率的箱线图

探索功能数量

用于拟合每个决策树的特征数量可以变化。

像改变样本的数量一样,改变特征的数量会在模型中引入额外的方差,这可能会提高表现,尽管这可能需要增加树的数量。

每个树使用的特征数量被视为随机样本,由“ max_features ”参数指定,默认为训练数据集中的所有特征。

下面的示例探讨了 1 到 20 之间的测试数据集的特征数量对模型表现的影响。

# explore gradient boosting number of features on performance
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.ensemble import GradientBoostingClassifier
from matplotlib import pyplot

# get the dataset
def get_dataset():
	X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=7)
	return X, y

# get a list of models to evaluate
def get_models():
	models = dict()
	# explore number of features from 1 to 20
	for i in range(1,21):
		models[str(i)] = GradientBoostingClassifier(max_features=i)
	return models

# evaluate a given model using cross-validation
def evaluate_model(model, X, y):
	# define the evaluation procedure
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	# evaluate the model and collect the results
	scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	return scores

# define dataset
X, y = get_dataset()
# get the models to evaluate
models = get_models()
# evaluate the models and store results
results, names = list(), list()
for name, model in models.items():
	# evaluate the model
	scores = evaluate_model(model, X, y)
	# store the results
	results.append(scores)
	names.append(name)
	# summarize the performance along the way
	print('>%s %.3f (%.3f)' % (name, mean(scores), std(scores)))
# plot model performance for comparison
pyplot.boxplot(results, labels=names, showmeans=True)
pyplot.show()

运行该示例首先报告每个已配置特征数量的平均准确率。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到平均表现增加到功能数量的一半左右,并且在此之后保持一定水平。令人惊讶的是,去掉一半的输入变量效果如此之小。

>1 0.864 (0.036)
>2 0.885 (0.032)
>3 0.891 (0.031)
>4 0.893 (0.036)
>5 0.898 (0.030)
>6 0.898 (0.032)
>7 0.892 (0.032)
>8 0.901 (0.032)
>9 0.900 (0.029)
>10 0.895 (0.034)
>11 0.899 (0.032)
>12 0.899 (0.030)
>13 0.898 (0.029)
>14 0.900 (0.033)
>15 0.901 (0.032)
>16 0.897 (0.028)
>17 0.902 (0.034)
>18 0.899 (0.032)
>19 0.899 (0.032)
>20 0.899 (0.030)

为每个配置数量的树的准确度分数的分布创建一个方框和须图。

我们可以看到提高模型表现的总体趋势,可能在八九个特性左右达到峰值,并保持一定水平。

Box Plot of Gradient Boosting Ensemble Number of Features vs. Classification Accuracy

梯度提升集成特征数量与分类准确率的箱线图

探索学习率

学习率控制每个模型对集成预测的贡献量。

较小的速率可能需要集成中更多的决策树,而较大的速率可能需要具有较少树的集成。在对数标度上探索学习率值是很常见的,例如在非常小的值如 0.0001 和 1.0 之间。

学习率可以通过“ learning_rate ”参数控制,默认为 0.1。

下面的示例探讨了学习率,并比较了 0.0001 和 1.0 之间的值的效果。

# explore gradient boosting ensemble learning rate effect on performance
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.ensemble import GradientBoostingClassifier
from matplotlib import pyplot

# get the dataset
def get_dataset():
	X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=7)
	return X, y

# get a list of models to evaluate
def get_models():
	models = dict()
	# define learning rates to explore
	for i in [0.0001, 0.001, 0.01, 0.1, 1.0]:
		key = '%.4f' % i
		models[key] = GradientBoostingClassifier(learning_rate=i)
	return models

# evaluate a given model using cross-validation
def evaluate_model(model, X, y):
	# define the evaluation procedure
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	# evaluate the model and collect the results
	scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	return scores

# define dataset
X, y = get_dataset()
# get the models to evaluate
models = get_models()
# evaluate the models and store results
results, names = list(), list()
for name, model in models.items():
	# evaluate the model
	scores = evaluate_model(model, X, y)
	# store the results
	results.append(scores)
	names.append(name)
	# summarize the performance along the way
	print('>%s %.3f (%.3f)' % (name, mean(scores), std(scores)))
# plot model performance for comparison
pyplot.boxplot(results, labels=names, showmeans=True)
pyplot.show()

运行示例首先报告每个配置的学习率的平均准确性。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到,较大的学习率会在该数据集上产生更好的表现。我们预计,为较小的学习率向集合中添加更多的树将进一步提升表现。

这突出了树的数量(训练速度)和学习率之间的权衡,例如,我们可以通过使用更少的树和更大的学习率来更快地拟合模型。

>0.0001 0.761 (0.043)
>0.0010 0.781 (0.034)
>0.0100 0.836 (0.034)
>0.1000 0.899 (0.030)
>1.0000 0.908 (0.025)

为每个配置数量的树的准确度分数的分布创建一个方框和须图。

我们可以看到模型表现随着学习率的提高而提高的总趋势。

Box Plot of Gradient Boosting Ensemble Learning Rate vs. Classification Accuracy

梯度提升集成学习率与分类准确率的箱线图

探索树的深度

就像改变用于拟合每棵决策树的样本和特征的数量一样,改变每棵树的深度是梯度提升的另一个重要超参数。

树深度控制每棵树对训练数据集的专门化程度:它可能有多一般或多复杂。优选不太浅和一般的树(如 AdaBoost),不太深和专门化的树(如引导聚合)。

梯度提升在中等深度的树中表现良好,在技能和通用性之间找到了平衡。

树深度通过“最大深度参数控制,默认为 3。

下面的示例探讨了 1 到 10 之间的树深度以及对模型表现的影响。

# explore gradient boosting tree depth effect on performance
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.ensemble import GradientBoostingClassifier
from matplotlib import pyplot

# get the dataset
def get_dataset():
	X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=7)
	return X, y

# get a list of models to evaluate
def get_models():
	models = dict()
	# define max tree depths to explore between 1 and 10
	for i in range(1,11):
		models[str(i)] = GradientBoostingClassifier(max_depth=i)
	return models

# evaluate a given model using cross-validation
def evaluate_model(model, X, y):
	# define the evaluation procedure
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	# evaluate the model and collect the results
	scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	return scores

# define dataset
X, y = get_dataset()
# get the models to evaluate
models = get_models()
# evaluate the models and store results
results, names = list(), list()
for name, model in models.items():
	# evaluate the model
	scores = evaluate_model(model, X, y)
	# store the results
	results.append(scores)
	names.append(name)
	# summarize the performance along the way
	print('>%s %.3f (%.3f)' % (name, mean(scores), std(scores)))
# plot model performance for comparison
pyplot.boxplot(results, labels=names, showmeans=True)
pyplot.show()

运行该示例首先报告每个配置的树深度的平均准确率。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到表现随着树的深度而提高,可能在深度 3 到 6 左右达到峰值,之后更深、更专门化的树会导致表现下降。

>1 0.834 (0.031)
>2 0.877 (0.029)
>3 0.899 (0.030)
>4 0.905 (0.032)
>5 0.916 (0.030)
>6 0.912 (0.031)
>7 0.908 (0.033)
>8 0.888 (0.031)
>9 0.853 (0.036)
>10 0.835 (0.034)

为每个配置的树深度的准确率分数分布创建一个方框和须图。

我们可以看到模型表现随着树的深度增加到一定程度的总体趋势,之后表现开始随着过度专门化的树而迅速下降。

Box Plot of Gradient Boosting Ensemble Tree Depth vs. Classification Accuracy

梯度提升集成树深度与分类准确率的箱线图

网格搜索超参数

梯度提升对算法的配置具有挑战性,因为许多影响模型在训练数据上的行为的关键超参数和超参数相互作用。

因此,使用搜索过程来发现模型超参数的配置是一个好的实践,该配置对于给定的预测建模问题是有效的或最好的。流行的搜索过程包括随机搜索和网格搜索。

在这一节中,我们将看到网格搜索的关键超参数的共同范围的梯度提升算法,你可以使用作为你自己的项目的起点。这可以通过使用 GridSearchCV 类并指定将模型超参数名称映射到要搜索的值的字典来实现。

在这种情况下,我们将网格搜索梯度提升的四个关键超参数:集成中使用的树的数量、学习率、用于训练每棵树的子样本大小以及每棵树的最大深度。我们将为每个超参数使用一系列流行的表现良好的值。

每个配置组合将使用重复的 k 倍交叉验证进行评估,配置将使用平均得分进行比较,在这种情况下,使用分类准确率。

下面列出了在我们的合成类别数据集上网格搜索梯度提升算法的关键超参数的完整示例。

# example of grid searching key hyperparameters for gradient boosting on a classification dataset
from sklearn.datasets import make_classification
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import GradientBoostingClassifier
# define dataset
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=7)
# define the model with default hyperparameters
model = GradientBoostingClassifier()
# define the grid of values to search
grid = dict()
grid['n_estimators'] = [10, 50, 100, 500]
grid['learning_rate'] = [0.0001, 0.001, 0.01, 0.1, 1.0]
grid['subsample'] = [0.5, 0.7, 1.0]
grid['max_depth'] = [3, 7, 9]
# define the evaluation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# define the grid search procedure
grid_search = GridSearchCV(estimator=model, param_grid=grid, n_jobs=-1, cv=cv, scoring='accuracy')
# execute the grid search
grid_result = grid_search.fit(X, y)
# summarize the best score and configuration
print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
# summarize all scores that were evaluated
means = grid_result.cv_results_['mean_test_score']
stds = grid_result.cv_results_['std_test_score']
params = grid_result.cv_results_['params']
for mean, stdev, param in zip(means, stds, params):
    print("%f (%f) with: %r" % (mean, stdev, param))

运行该示例可能需要一段时间,具体取决于您的硬件。在运行结束时,首先报告获得最佳分数的配置,然后是所考虑的所有其他配置的分数。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到,学习率为 0.1、最大深度为 7 级、500 棵树和子样本为 70%的配置表现最好,分类准确率约为 94.6%。

尽管在这种情况下没有测试这些配置,以确保网格搜索在合理的时间内完成,但该模型在有更多树(如 1000 或 5000 棵树)的情况下可能会表现得更好。

Best: 0.946667 using {'learning_rate': 0.1, 'max_depth': 7, 'n_estimators': 500, 'subsample': 0.7}
0.529667 (0.089012) with: {'learning_rate': 0.0001, 'max_depth': 3, 'n_estimators': 10, 'subsample': 0.5}
0.525667 (0.077875) with: {'learning_rate': 0.0001, 'max_depth': 3, 'n_estimators': 10, 'subsample': 0.7}
0.524000 (0.072874) with: {'learning_rate': 0.0001, 'max_depth': 3, 'n_estimators': 10, 'subsample': 1.0}
0.772667 (0.037500) with: {'learning_rate': 0.0001, 'max_depth': 3, 'n_estimators': 50, 'subsample': 0.5}
0.767000 (0.037696) with: {'learning_rate': 0.0001, 'max_depth': 3, 'n_estimators': 50, 'subsample': 0.7}
...

常见问题

在这一节中,我们将仔细看看梯度提升集成过程中的一些常见症结。

问:集成应该用什么算法?

从技术上讲,任何支持实例加权的高方差算法都可以用作集成的基础。

用于速度和模型表现的最常见算法是具有有限树深度的决策树,例如在 4 到 8 级之间。

问:应该用多少个文工团成员?

集成中的树的数量应该根据数据集的具体情况和其他超参数(如学习率)进行调整。

问:文工团不会因为树木太多而过度吗?

是的,梯度推进模型可能会过度。

使用搜索过程(如网格搜索)仔细选择模型超参数非常重要。

学习率,也称为收缩,可以设置为较小的值,以便随着集成中使用的模型数量的增加而降低学习率,进而降低过拟合的影响。

问:梯度提升有哪些弊端?

梯度提升可能很难配置,通常需要网格搜索或类似的搜索过程。

训练梯度提升模型可能非常慢,因为树必须按顺序添加,不像基于装袋和堆叠的模型,集成成员可以并行训练。

问:哪些问题很适合提振?

梯度提升在广泛的回归和分类预测建模问题上表现良好。

它可能是结构化数据(表格数据)最流行的算法之一,因为它的平均表现非常好。

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

教程

报纸

蜜蜂

文章

摘要

在本教程中,您发现了如何为分类和回归开发梯度提升集成。

具体来说,您了解到:

  • 梯度提升集成是由顺序添加到模型中的决策树创建的集成。
  • 如何用 Sklearn 使用梯度提升集成进行分类和回归。
  • 如何探索梯度提升模型超参数对模型表现的影响。

你有什么问题吗? 在下面的评论中提问,我会尽力回答。

将 Sklearn、XGBoost、LightGBM 和 CatBoost 用于梯度提升

原文:machinelearningmastery.com/gradient-bo…

最后更新于 2021 年 4 月 27 日

梯度提升是一种强大的集成机器学习算法。

它适用于结构化预测建模问题,如表格数据的分类和回归,通常是机器学习竞赛中获胜解决方案的主要算法或主要算法之一,就像 Kaggle 上的算法一样。

有许多可用的梯度提升实现,包括 SciPy 中的标准实现和高效的第三方库。每一个都使用不同的接口,甚至不同的算法名称。

在本教程中,您将发现如何在 Python 中使用梯度提升模型进行分类和回归。

为 Python 中梯度提升的四种主要实现提供了标准化的代码示例,供您复制粘贴并在自己的预测建模项目中使用。

完成本教程后,您将知道:

  • 梯度提升是一种集成算法,通过最小化误差梯度来适应增强的决策树。
  • 如何使用 Sklearn 评估和使用梯度提升,包括梯度提升机和基于直方图的算法。
  • 如何评估和使用第三方梯度提升算法,包括 XGBoost、LightGBM 和 CatBoost。

用我的新书Python 集成学习算法启动你的项目,包括分步教程和所有示例的 Python 源代码文件。

我们开始吧。

Gradient Boosting with Sklearn, XGBoost, LightGBM, and CatBoost

使用 Sklearn、XGBoost、LightGBM 和 CatBoost 进行梯度提升 图片由约翰提供,保留部分权利。

教程概述

本教程分为五个部分;它们是:

  1. 梯度提升概述
  2. 使用 Scikit 进行梯度提升-学习
    1. 库安装
    2. 测试问题
    3. 梯度升压
    4. 基于直方图的梯度提升
  3. 带 XGBoost 的梯度升压
    1. 库安装
    2. 用于分类的扩展包
    3. 用于回归的 XGBoost
  4. 用 LightGBM 进行梯度升压
    1. 库安装
    2. 用于分类的 LightGBM
    3. 回归之光
  5. 利用 CatBoost 实现梯度升压
    1. 库安装
    2. 分类的分类增强
    3. 回归的助力

梯度提升概述

梯度提升是指一类集成机器学习算法,可用于分类或回归预测建模问题。

梯度提升也称为梯度树增强、随机梯度提升(扩展)和梯度提升机,简称 GBM。

集成是由决策树模型构建的。树被一次一个地添加到集合中,并且适合于校正由先前模型产生的预测误差。这是一种称为 boosting 的集成机器学习模型。

使用任意可微损失函数和梯度下降优化算法拟合模型。这给这项技术起了一个名字,“梯度提升”,因为随着模型的拟合,损失梯度被最小化,很像一个神经网络。

梯度提升是一种有效的机器学习算法,并且通常是用于在表格和类似结构化数据集上赢得机器学习竞赛(如 Kaggle)的主要算法或主要算法之一。

:在本教程中,我们将不讨论梯度提升算法背后的理论。

有关梯度提升算法的更多信息,请参见教程:

该算法提供了超参数,这些超参数应该而且可能必须针对特定数据集进行调整。虽然有许多超参数需要调整,但最重要的可能如下:

  • 模型中树或估计量的数量。
  • 模型的学习率。
  • 随机模型的行列采样率。
  • 最大树深。
  • 最小树重。
  • 正则项α和λ。

:在本教程中,我们将不探讨如何配置或调整梯度提升算法的配置。

有关调整梯度提升算法的超参数的更多信息,请参见教程:

Python 中有许多梯度提升算法的实现。也许最常用的实现是 Sklearn 库提供的版本。

可以使用额外的第三方库来提供算法的计算高效的替代实现,这些实现通常在实践中获得更好的结果。例子包括 XGBoost 库、LightGBM 库和 CatBoost 库。

你有不同喜欢的梯度提升实现吗? 在下面的评论里告诉我。

在预测建模项目中使用梯度提升时,您可能希望测试算法的每个实现。

本教程提供了梯度提升算法在分类和回归预测建模问题上的每个实现的示例,您可以将其复制粘贴到项目中。

让我们依次看一下每一个。

:本教程中我们不是比较算法的表现。相反,我们提供代码示例来演示如何使用每个不同的实现。因此,我们使用合成测试数据集来演示评估和预测每个实现。

本教程假设您已经安装了 Python 和 SciPy。如果您需要帮助,请参阅教程:

使用 Sklearn 进行梯度提升

在本节中,我们将回顾如何在 Sklearn 库中使用梯度提升算法实现。

库安装

首先,让我们安装库。

不要跳过这一步,因为您需要确保安装了最新版本。

您可以使用 pip Python 安装程序安装 Sklearn 库,如下所示:

sudo pip install Sklearn

有关特定于您的平台的其他安装说明,请参见:

接下来,让我们确认库已安装,并且您使用的是现代版本。

运行以下脚本打印库版本号。

# check Sklearn version
import sklearn
print(sklearn.__version__)

运行该示例时,您应该会看到以下版本号或更高版本号。

0.22.1

测试问题

我们将演示用于分类和回归的梯度提升算法。

因此,我们将使用 Sklearn 库中的合成测试问题。

类别数据集

我们将使用 make_classification()函数创建一个测试二进制类别数据集。

数据集将有 1,000 个示例,有 10 个输入要素,其中 5 个是信息性的,其余 5 个是冗余的。我们将修复随机数种子,以确保每次运行代码时得到相同的例子。

下面列出了创建和汇总数据集的示例。

# test classification dataset
from sklearn.datasets import make_classification
# define dataset
X, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=5, random_state=1)
# summarize the dataset
print(X.shape, y.shape)

运行该示例将创建数据集,并确认样本和要素的预期数量。

(1000, 10) (1000,)
回归数据集

我们将使用make _ revolution()函数创建一个测试回归数据集。

与类别数据集一样,回归数据集将有 1,000 个示例,有 10 个输入要素,其中 5 个是信息性的,其余 5 个是冗余的。

# test regression dataset
from sklearn.datasets import make_regression
# define dataset
X, y = make_regression(n_samples=1000, n_features=10, n_informative=5, random_state=1)
# summarize the dataset
print(X.shape, y.shape)

运行该示例将创建数据集,并确认样本和要素的预期数量。

(1000, 10) (1000,)

接下来,让我们看看如何在 Sklearn 中开发梯度提升模型。

梯度升压

Sklearn 库通过GradientBoostingClassifiergradientboostingretriever类提供回归和分类的 GBM 算法。

让我们依次仔细看看每一个。

分级梯度推进机

下面的示例首先使用重复的 k 倍交叉验证在测试问题上评估一个gradientboosting 分类器,并报告平均准确度。然后在所有可用数据上拟合单一模型,并进行单一预测。

下面列出了完整的示例。

# gradient boosting for classification in Sklearn
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from matplotlib import pyplot
# define dataset
X, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=5, random_state=1)
# evaluate the model
model = GradientBoostingClassifier()
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# fit the model on the whole dataset
model = GradientBoostingClassifier()
model.fit(X, y)
# make a single prediction
row = [[2.56999479, -0.13019997, 3.16075093, -4.35936352, -1.61271951, -1.39352057, -2.48924933, -1.93094078, 3.26130366, 2.05692145]]
yhat = model.predict(row)
print('Prediction: %d' % yhat[0])

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

运行该示例首先使用重复的 k 倍交叉验证报告模型的评估,然后使用模型对整个数据集进行单次预测的结果。

Accuracy: 0.915 (0.025)
Prediction: 1
回归梯度提升机

下面的示例首先使用重复的 K 折交叉验证对测试问题评估一个gradientboostingrevoller,并报告平均绝对误差。然后在所有可用数据上拟合单一模型,并进行单一预测。

下面列出了完整的示例。

# gradient boosting for regression in Sklearn
from numpy import mean
from numpy import std
from sklearn.datasets import make_regression
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedKFold
from matplotlib import pyplot
# define dataset
X, y = make_regression(n_samples=1000, n_features=10, n_informative=5, random_state=1)
# evaluate the model
model = GradientBoostingRegressor()
cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1, error_score='raise')
print('MAE: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# fit the model on the whole dataset
model = GradientBoostingRegressor()
model.fit(X, y)
# make a single prediction
row = [[2.02220122, 0.31563495, 0.82797464, -0.30620401, 0.16003707, -1.44411381, 0.87616892, -0.50446586, 0.23009474, 0.76201118]]
yhat = model.predict(row)
print('Prediction: %.3f' % yhat[0])

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

运行该示例首先使用重复的 k 倍交叉验证报告模型的评估,然后使用模型对整个数据集进行单次预测的结果。

MAE: -11.854 (1.121)
Prediction: -80.661

基于直方图的梯度提升

Sklearn 库提供了梯度提升算法的替代实现,称为基于直方图的梯度提升。

这是一种实现梯度树增强的替代方法,灵感来自 LightGBM 库(稍后将详细描述)。这个实现是通过历史梯度提升分类器历史梯度提升回归器类提供的。

基于直方图的梯度提升方法的主要优势是速度。这些实现旨在更快地适应训练数据。

在编写本文时,这是一个实验性的实现,需要在代码中添加以下代码行,以便能够访问这些类。

from sklearn.experimental import enable_hist_gradient_boosting

如果没有这一行,您将看到如下错误:

ImportError: cannot import name 'HistGradientBoostingClassifier'

或者

ImportError: cannot import name 'HistGradientBoostingRegressor'

让我们仔细看看如何使用这个实现。

基于直方图的梯度提升分类机

下面的示例首先使用重复的 k 倍交叉验证对测试问题评估一个HistGradientBoostingCollector,并报告平均准确度。然后在所有可用数据上拟合单一模型,并进行单一预测。

下面列出了完整的示例。

# histogram-based gradient boosting for classification in Sklearn
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.experimental import enable_hist_gradient_boosting
from sklearn.ensemble import HistGradientBoostingClassifier
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from matplotlib import pyplot
# define dataset
X, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=5, random_state=1)
# evaluate the model
model = HistGradientBoostingClassifier()
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# fit the model on the whole dataset
model = HistGradientBoostingClassifier()
model.fit(X, y)
# make a single prediction
row = [[2.56999479, -0.13019997, 3.16075093, -4.35936352, -1.61271951, -1.39352057, -2.48924933, -1.93094078, 3.26130366, 2.05692145]]
yhat = model.predict(row)
print('Prediction: %d' % yhat[0])

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

运行该示例首先使用重复的 k 倍交叉验证报告模型的评估,然后使用模型对整个数据集进行单次预测的结果。

Accuracy: 0.935 (0.024)
Prediction: 1
基于直方图的梯度提升回归机

下面的示例首先使用重复的 K 折交叉验证对测试问题评估一个HistGradientBoostingResolver,并报告平均绝对误差。然后在所有可用数据上拟合单一模型,并进行单一预测。

下面列出了完整的示例。

# histogram-based gradient boosting for regression in Sklearn
from numpy import mean
from numpy import std
from sklearn.datasets import make_regression
from sklearn.experimental import enable_hist_gradient_boosting
from sklearn.ensemble import HistGradientBoostingRegressor
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedKFold
from matplotlib import pyplot
# define dataset
X, y = make_regression(n_samples=1000, n_features=10, n_informative=5, random_state=1)
# evaluate the model
model = HistGradientBoostingRegressor()
cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1, error_score='raise')
print('MAE: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# fit the model on the whole dataset
model = HistGradientBoostingRegressor()
model.fit(X, y)
# make a single prediction
row = [[2.02220122, 0.31563495, 0.82797464, -0.30620401, 0.16003707, -1.44411381, 0.87616892, -0.50446586, 0.23009474, 0.76201118]]
yhat = model.predict(row)
print('Prediction: %.3f' % yhat[0])

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

运行该示例首先使用重复的 k 倍交叉验证报告模型的评估,然后使用模型对整个数据集进行单次预测的结果。

MAE: -12.723 (1.540)
Prediction: -77.837

带 XGBoost 的梯度升压

XGBoost ,是“极限梯度提升的缩写,是一个提供梯度提升算法高效实现的库。

XGBoost 实现的主要好处是计算效率和更好的模型表现。

有关 XGBoost 的优势和功能的更多信息,请参见教程:

库安装

您可以使用 pip Python 安装程序安装 XGBoost 库,如下所示:

sudo pip install xgboost

有关特定于您的平台的其他安装说明,请参见:

接下来,让我们确认库已安装,并且您使用的是现代版本。

运行以下脚本打印库版本号。

# check xgboost version
import xgboost
print(xgboost.__version__)

运行该示例时,您应该会看到以下版本号或更高版本号。

1.0.1

XGBoost 库提供了包装器类,因此高效的算法实现可以与 Sklearn 库一起使用,特别是通过 XGBClassifierxgbreversor类。

让我们依次仔细看看每一个。

用于分类的扩展包

下面的示例首先使用重复的 k 倍交叉验证评估测试问题上的xbindicator,并报告平均准确度。然后对所有可用数据拟合单一模型,并进行单一预测。

下面列出了完整的示例。

# xgboost for classification
from numpy import asarray
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from xgboost import XGBClassifier
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from matplotlib import pyplot
# define dataset
X, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=5, random_state=1)
# evaluate the model
model = XGBClassifier()
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# fit the model on the whole dataset
model = XGBClassifier()
model.fit(X, y)
# make a single prediction
row = [2.56999479, -0.13019997, 3.16075093, -4.35936352, -1.61271951, -1.39352057, -2.48924933, -1.93094078, 3.26130366, 2.05692145]
row = asarray(row).reshape((1, len(row)))
yhat = model.predict(row)
print('Prediction: %d' % yhat[0])

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

运行该示例首先使用重复的 k 倍交叉验证报告模型的评估,然后使用模型对整个数据集进行单次预测的结果。

Accuracy: 0.936 (0.019)
Prediction: 1

用于回归的 XGBoost

下面的示例首先使用重复的 k 倍交叉验证对测试问题评估一个xgbreversor,并报告平均绝对误差。然后在所有可用数据上拟合单一模型,并进行单一预测。

下面列出了完整的示例。

# xgboost for regression
from numpy import asarray
from numpy import mean
from numpy import std
from sklearn.datasets import make_regression
from xgboost import XGBRegressor
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedKFold
from matplotlib import pyplot
# define dataset
X, y = make_regression(n_samples=1000, n_features=10, n_informative=5, random_state=1)
# evaluate the model
model = XGBRegressor(objective='reg:squarederror')
cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1, error_score='raise')
print('MAE: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# fit the model on the whole dataset
model = XGBRegressor(objective='reg:squarederror')
model.fit(X, y)
# make a single prediction
row = [2.02220122, 0.31563495, 0.82797464, -0.30620401, 0.16003707, -1.44411381, 0.87616892, -0.50446586, 0.23009474, 0.76201118]
row = asarray(row).reshape((1, len(row)))
yhat = model.predict(row)
print('Prediction: %.3f' % yhat[0])

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

运行该示例首先使用重复的 k 倍交叉验证报告模型的评估,然后使用模型对整个数据集进行单次预测的结果。

MAE: -15.048 (1.316)
Prediction: -93.434

用 LightGBM 进行梯度升压

LightGBM 是 Light Gradient Boosted Machine 的缩写,是微软开发的一个库,提供了一个高效的梯度提升算法的实现。

LightGBM 的主要好处是对训练算法的改变,这使得过程大大加快,并且在许多情况下,产生了更有效的模型。

有关 LightGBM 算法的更多技术细节,请参见论文:

库安装

您可以使用 pip Python 安装程序安装 LightGBM 库,如下所示:

sudo pip install lightgbm

有关特定于您的平台的其他安装说明,请参见:

接下来,让我们确认库已安装,并且您使用的是现代版本。

运行以下脚本打印库版本号。

# check lightgbm version
import lightgbm
print(lightgbm.__version__)

运行该示例时,您应该会看到以下版本号或更高版本号。

2.3.1

LightGBM 库提供了包装类,因此高效的算法实现可以与 Sklearn 库一起使用,特别是通过 LGBMClassifierlgbmreversor类。

让我们依次仔细看看每一个。

用于分类的 LightGBM

下面的示例首先使用重复的 k 倍交叉验证对测试问题评估一个 LGBMClassifier ,并报告平均准确度。然后在所有可用数据上拟合单一模型,并进行单一预测。

下面列出了完整的示例。

# lightgbm for classification
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from lightgbm import LGBMClassifier
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from matplotlib import pyplot
# define dataset
X, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=5, random_state=1)
# evaluate the model
model = LGBMClassifier()
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# fit the model on the whole dataset
model = LGBMClassifier()
model.fit(X, y)
# make a single prediction
row = [[2.56999479, -0.13019997, 3.16075093, -4.35936352, -1.61271951, -1.39352057, -2.48924933, -1.93094078, 3.26130366, 2.05692145]]
yhat = model.predict(row)
print('Prediction: %d' % yhat[0])

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

运行该示例首先使用重复的 k 倍交叉验证报告模型的评估,然后使用模型对整个数据集进行单次预测的结果。

Accuracy: 0.934 (0.021)
Prediction: 1

回归之光

下面的示例首先使用重复的 k 倍交叉验证对测试问题评估一个lgbmrejector,并报告平均绝对误差。然后在所有可用数据上拟合单一模型,并进行单一预测。

下面列出了完整的示例。

# lightgbm for regression
from numpy import mean
from numpy import std
from sklearn.datasets import make_regression
from lightgbm import LGBMRegressor
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedKFold
from matplotlib import pyplot
# define dataset
X, y = make_regression(n_samples=1000, n_features=10, n_informative=5, random_state=1)
# evaluate the model
model = LGBMRegressor()
cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1, error_score='raise')
print('MAE: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# fit the model on the whole dataset
model = LGBMRegressor()
model.fit(X, y)
# make a single prediction
row = [[2.02220122, 0.31563495, 0.82797464, -0.30620401, 0.16003707, -1.44411381, 0.87616892, -0.50446586, 0.23009474, 0.76201118]]
yhat = model.predict(row)
print('Prediction: %.3f' % yhat[0])

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

运行该示例首先使用重复的 k 倍交叉验证报告模型的评估,然后使用模型对整个数据集进行单次预测的结果。

MAE: -12.739 (1.408)
Prediction: -82.040

利用 CatBoost 实现梯度升压

CatBoost 是在 Yandex 开发的第三方库,提供了梯度 boosting 算法的高效实现。

CatBoost 的主要好处(除了计算速度的提高)是支持分类输入变量。这使库的名称为“类别梯度提升”

有关 CatBoost 算法的更多技术细节,请参见论文:

库安装

您可以使用 pip Python 安装程序安装 CatBoost 库,如下所示:

sudo pip install catboost

有关特定于您的平台的其他安装说明,请参见:

  • cat boost 安装指南

接下来,让我们确认库已安装,并且您使用的是现代版本。

运行以下脚本打印库版本号。

# check catboost version
import catboost
print(catboost.__version__)

运行该示例时,您应该会看到以下版本号或更高版本号。

0.21

CatBoost 库提供了包装器类,因此高效的算法实现可以与 Sklearn 库一起使用,特别是通过CatBoost 分类器CatBoost 渐行渐远器类。

让我们依次仔细看看每一个。

分类的分类增强

下面的示例首先使用重复的 k 倍交叉验证在测试问题上评估一个 CatBoostClassifier ,并报告平均准确度。然后在所有可用数据上拟合单一模型,并进行单一预测。

下面列出了完整的示例。

# catboost for classification
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from catboost import CatBoostClassifier
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from matplotlib import pyplot
# define dataset
X, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=5, random_state=1)
# evaluate the model
model = CatBoostClassifier(verbose=0, n_estimators=100)
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# fit the model on the whole dataset
model = CatBoostClassifier(verbose=0, n_estimators=100)
model.fit(X, y)
# make a single prediction
row = [[2.56999479, -0.13019997, 3.16075093, -4.35936352, -1.61271951, -1.39352057, -2.48924933, -1.93094078, 3.26130366, 2.05692145]]
yhat = model.predict(row)
print('Prediction: %d' % yhat[0])

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

运行该示例首先使用重复的 k 倍交叉验证报告模型的评估,然后使用模型对整个数据集进行单次预测的结果。

Accuracy: 0.931 (0.026)
Prediction: 1

回归的助力

下面的示例首先使用重复的 k 倍交叉验证对测试问题评估一个catbootstregressor,并报告平均绝对误差。然后在所有可用数据上拟合单一模型,并进行单一预测。

下面列出了完整的示例。

# catboost for regression
from numpy import mean
from numpy import std
from sklearn.datasets import make_regression
from catboost import CatBoostRegressor
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedKFold
from matplotlib import pyplot
# define dataset
X, y = make_regression(n_samples=1000, n_features=10, n_informative=5, random_state=1)
# evaluate the model
model = CatBoostRegressor(verbose=0, n_estimators=100)
cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1, error_score='raise')
print('MAE: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# fit the model on the whole dataset
model = CatBoostRegressor(verbose=0, n_estimators=100)
model.fit(X, y)
# make a single prediction
row = [[2.02220122, 0.31563495, 0.82797464, -0.30620401, 0.16003707, -1.44411381, 0.87616892, -0.50446586, 0.23009474, 0.76201118]]
yhat = model.predict(row)
print('Prediction: %.3f' % yhat[0])

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

运行该示例首先使用重复的 k 倍交叉验证报告模型的评估,然后使用模型对整个数据集进行单次预测的结果。

MAE: -9.281 (0.951)
Prediction: -74.212

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

教程

报纸

蜜蜂

文章

摘要

在本教程中,您发现了如何在 Python 中使用梯度提升模型进行分类和回归。

具体来说,您了解到:

  • 梯度提升是一种集成算法,通过最小化误差梯度来适应增强的决策树。
  • 如何使用 Sklearn 评估和使用梯度提升,包括梯度提升机和基于直方图的算法。
  • 如何评估和使用包括 XGBoost、LightGBM 和 CatBoost 在内的第三方梯度提升算法。

你有什么问题吗? 在下面的评论中提问,我会尽力回答。

Python 中的生长和修剪集成

原文:machinelearningmastery.com/growing-and…

集成成员选择是指优化集成组成的算法。

这可能涉及从可用模型中生长一个集合,或者从完全定义的集合中修剪成员。

目标通常是在对集成表现影响很小或没有影响的情况下降低集成的模型或计算复杂度,并且在某些情况下找到比直接盲目使用所有贡献模型更好的集成成员组合。

在本教程中,您将发现如何从零开始开发集成选择算法。

完成本教程后,您将知道:

  • 集成选择包括选择集成成员的子集,这导致比使用所有成员更低的复杂性,有时还会带来更好的表现。
  • 如何开发和评估贪婪集成剪枝分类算法?
  • 如何开发和评估一个算法贪婪地从零开始增长一个集合。

用我的新书Python 集成学习算法启动你的项目,包括分步教程和所有示例的 Python 源代码文件。

我们开始吧。

Growing and Pruning Ensembles in Python

Python 中的生长和修剪集成 图片由 FaBio C 提供,保留部分权利。

教程概述

本教程分为四个部分;它们是:

  1. 全体成员选择
  2. 基线模型和投票
  3. 集成修剪示例
  4. 集合增长示例

全体成员选择

投票堆叠集合通常会组合来自一组不同模型类型的预测。

虽然集成团可能有大量的集成成员,但很难知道集成团正在使用最佳的成员组合。例如,不是简单地使用所有成员,而是可以通过添加一个或多个不同的模型类型或删除一个或多个模型来获得更好的结果。

这可以通过使用加权平均集成和使用优化算法为每个成员找到合适的权重来解决,允许一些成员具有零权重,这有效地将他们从集成中移除。加权平均集合的问题是,所有模型仍然是集合的一部分,这可能需要比开发和维护更复杂的集合。

另一种方法是优化集成本身的构成。自动选择或优化集成成员的一般方法被称为集成选择。

两种常见的方法包括集成生长和集成修剪。

  • 集成成长:向集成中添加成员,直到没有观察到进一步的改善。
  • 集合修剪:从集合中移除成员,直到没有观察到进一步的改进。

集成增长是一种技术,其中模型从没有成员开始,并涉及添加新成员,直到没有观察到进一步的改进。这可以用贪婪的方式来执行,一次只添加一个成员,前提是它们导致模型表现的提高。

集成修剪是一种技术,其中模型从所有正在考虑的可能成员开始,并从集成中移除成员,直到没有观察到进一步的改进。这可以以贪婪的方式执行,即每次移除一个成员,并且仅当移除成员导致整体集合的表现提升时。

给定一组经过训练的个体学习器,而不是组合所有的学习器,集成修剪试图选择个体学习器的子集来组成集成。

—第 119 页,集成方法:基础和算法,2012。

集合修剪和增长的优点在于,它可以导致具有较小尺寸(较低复杂度)的集合和/或具有更好预测表现的集合。有时,如果能够大幅降低模型复杂性和维护负担,表现的小幅下降是可取的。或者,在某些项目中,预测技能比所有其他关注点都更重要,集成选择提供了另一种策略来尝试并充分利用贡献模型。

减少集成大小主要有两个原因:a)减少计算开销:较小的集成需要较少的计算开销;b)提高准确性:集成中的一些成员可能会降低整体的预测表现。

—第 119 页,使用集成方法的模式分类,2010。

出于计算效率的原因,在期望少量集成成员表现更好的情况下,集成增长可能是优选的,而在期望大量集成成员表现更好的情况下,集成修剪将更有效。

简单的贪婪集成生长和修剪与逐步特征选择技术有很多共同之处,例如回归中使用的技术(例如所谓的逐步回归)。

可以使用更复杂的技术,例如基于成员在数据集上的独立表现来选择要添加到集合或从集合中移除的成员,或者甚至通过使用全局搜索过程来尝试找到导致最佳整体表现的集合成员的组合。

人们可以在可能的不同集成子集的空间中执行启发式搜索,同时评估候选子集的集体价值。

—第 123 页,使用集成方法的模式分类,2010。

现在我们已经熟悉了集成选择方法,让我们来探索如何在 Sklearn 中实现集成修剪和集成增长。

基线模型和投票

在我们深入开发生长和修剪集成之前,让我们首先建立一个数据集和基线。

我们将使用一个综合二分类问题作为本研究的基础,由 make_classification()函数定义,有 5000 个例子和 20 个数字输入特征。

下面的示例定义了数据集并总结了其大小。

# test classification dataset
from sklearn.datasets import make_classification
# define dataset
X, y = make_classification(n_samples=5000, n_features=20, n_informative=10, n_redundant=10, random_state=1)
# summarize the dataset
print(X.shape, y.shape)

运行该示例以可重复的方式创建数据集,并报告行数和输入要素,符合我们的预期。

(5000, 20) (5000,)

接下来,我们可以选择一些候选模型,为我们的集成提供基础。

我们将使用五种标准的机器学习模型,包括逻辑回归、朴素贝叶斯、决策树、支持向量机和 k 近邻算法。

首先,我们可以定义一个函数,用默认超参数创建每个模型。每个模型将被定义为一个具有名称和模型对象的元组,然后被添加到列表中。这是一个有用的结构,既可以枚举模型及其名称,用于独立评估,也可以在以后的集合中使用。

下面的 get_models() 函数实现了这一点,并返回要考虑的模型列表。

# get a list of models to evaluate
def get_models():
	models = list()
	models.append(('lr', LogisticRegression()))
	models.append(('knn', KNeighborsClassifier()))
	models.append(('tree', DecisionTreeClassifier()))
	models.append(('nb', GaussianNB()))
	models.append(('svm', SVC(probability=True)))
	return models

然后,我们可以定义一个函数,该函数接受单个模型和数据集,并评估模型在数据集上的表现。我们将使用重复分层 k-fold 交叉验证来评估一个模型,该模型有 10 次折叠和 3 次重复,这是机器学习中的一个良好实践。

下面的 evaluate_model() 函数实现了这一点,并返回所有折叠和重复的分数列表。

# evaluate a give model using cross-validation
def evaluate_model(model, X, y):
	# define the model evaluation procedure
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	# evaluate the model
	scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	return scores

然后,我们可以创建模型列表并枚举它们,依次报告每个模型在合成数据集上的表现。

将这些联系在一起,完整的示例如下所示。

# evaluate standard models on the synthetic dataset
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.naive_bayes import GaussianNB
from matplotlib import pyplot

# get the dataset
def get_dataset():
	X, y = make_classification(n_samples=5000, n_features=20, n_informative=10, n_redundant=10, random_state=1)
	return X, y

# get a list of models to evaluate
def get_models():
	models = list()
	models.append(('lr', LogisticRegression()))
	models.append(('knn', KNeighborsClassifier()))
	models.append(('tree', DecisionTreeClassifier()))
	models.append(('nb', GaussianNB()))
	models.append(('svm', SVC(probability=True)))
	return models

# evaluate a give model using cross-validation
def evaluate_model(model, X, y):
	# define the model evaluation procedure
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	# evaluate the model
	scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	return scores

# define dataset
X, y = get_dataset()
# get the models to evaluate
models = get_models()
# evaluate the models and store results
results, names = list(), list()
for name, model in models:
	# evaluate model
	scores = evaluate_model(model, X, y)
	# store results
	results.append(scores)
	names.append(name)
	# summarize result
	print('>%s %.3f (%.3f)' % (name, mean(scores), std(scores)))
# plot model performance for comparison
pyplot.boxplot(results, labels=names, showmeans=True)
pyplot.show()

运行该示例会评估合成二进制类别数据集上的每个独立机器学习算法。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到 KNN 模型和 SVM 模型在这个数据集上表现最好,实现了大约 95.3%的平均分类准确率。

这些结果提供了一个表现基线,我们要求任何集成都要超过这个基线,才能被认为对这个数据集有用。

>lr 0.856 (0.014)
>knn 0.953 (0.008)
>tree 0.867 (0.014)
>nb 0.847 (0.021)
>svm 0.953 (0.010)

创建一个图形,显示每个算法的准确度分数分布的方框图和触须图。

我们可以看到,KNN 和 SVM 算法的表现比其他算法好得多,尽管所有算法在不同方面都很熟练。这可能会让他们成为集成团中值得考虑的好人选。

Box and Whisker Plots of Classification Accuracy for Standalone Machine Learning Models

独立机器学习模型分类准确率的盒须图

接下来,我们需要建立一个使用所有模型的基线集合。这将提供一个与生长和修剪方法的比较点,生长和修剪方法寻求用更小的模型子集获得更好的表现。

在这种情况下,我们将使用带有软投票的投票集合。这意味着每个模型将预测概率,并且概率将由集成模型求和,以选择每个输入样本的最终输出预测。

这可以通过使用 VotingClassifier 类来实现,其中成员是通过“估计器参数来设置的,该参数需要一个模型列表,其中每个模型都是一个具有名称和配置的模型对象的元组,就像我们在上一节中定义的那样。

然后,我们可以通过“投票”参数设置要执行的投票类型,在本例中,该参数设置为“

...
# create the ensemble
ensemble = VotingClassifier(estimators=models, voting='soft')

将这些联系在一起,下面的示例评估了合成二进制类别数据集上所有五个模型的投票集合。

# example of a voting ensemble with soft voting of ensemble members
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import VotingClassifier

# get the dataset
def get_dataset():
	X, y = make_classification(n_samples=5000, n_features=20, n_informative=10, n_redundant=10, random_state=1)
	return X, y

# get a list of models to evaluate
def get_models():
	models = list()
	models.append(('lr', LogisticRegression()))
	models.append(('knn', KNeighborsClassifier()))
	models.append(('tree', DecisionTreeClassifier()))
	models.append(('nb', GaussianNB()))
	models.append(('svm', SVC(probability=True)))
	return models

# define dataset
X, y = get_dataset()
# get the models to evaluate
models = get_models()
# create the ensemble
ensemble = VotingClassifier(estimators=models, voting='soft')
# define the evaluation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate the ensemble
scores = cross_val_score(ensemble, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
# summarize the result
print('Mean Accuracy: %.3f (%.3f)' % (mean(scores), std(scores)))

运行该示例使用重复的分层 k 折叠交叉验证来评估所有模型的软投票集合,并报告所有折叠和重复的平均准确性。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到投票集合实现了大约 92.8%的平均准确率。这比单独使用的 SVM 和 KNN 模型要低,后者的准确率约为 95.3%。

该结果强调了所有模型的简单投票集合导致在这种情况下模型具有更高的复杂性和更差的表现。也许我们可以找到一个成员子集,它比任何单个模型表现得更好,并且比简单地使用所有模型具有更低的复杂性。

Mean Accuracy: 0.928 (0.012)

接下来,我们将探索从集成中修剪成员。

集成修剪示例

在本节中,我们将探索如何从零开始开发一个贪婪的集成剪枝算法。

在这种情况下,我们将使用一个贪婪算法,它很容易实现。这包括从集合中移除一个成员,评估表演,并为集合中的每个成员重复这一过程。如果被移除,导致最佳表现提升的成员将被永久地从集合中移除,并重复该过程。这种情况一直持续到无法进一步改善为止。

它被称为“贪婪”算法,因为它在每一步都寻求最佳的改进。可能成员的最佳组合不在贪婪改进的路径上,在这种情况下,贪婪算法将找不到它,可以使用全局优化算法来代替。

首先,我们可以定义一个函数来评估候选模型列表。该函数将获取模型列表和数据集,并从模型列表中构建投票集成,并使用重复分层 K 折交叉验证评估其表现,返回平均分类准确率。

这个函数可以用来评估每个候选人从集合中的移除。下面的 evaluate_ensemble() 函数实现了这一点。

# evaluate a list of models
def evaluate_ensemble(models, X, y):
	# check for no models
	if len(models) == 0:
		return 0.0
	# create the ensemble
	ensemble = VotingClassifier(estimators=models, voting='soft')
	# define the evaluation procedure
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	# evaluate the ensemble
	scores = cross_val_score(ensemble, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	# return mean score
	return mean(scores)

接下来,我们可以定义一个执行一轮修剪的函数。

首先,用当前在集合中的所有模型建立表现基线。然后枚举模型列表并依次移除每个模型,并在集成上评估移除模型的效果。如果删除导致表现提高,则会记录新的分数和已删除的特定模型。

重要的是,试删除是在模型列表的副本上执行的,而不是在模型的主列表本身上。这是为了确保我们只从列表中删除一个集成成员,一旦我们知道它将从当前步骤中可能被删除的所有成员中产生尽可能好的改进。

下面的 prune_round() 函数在给定集合和数据集中当前模型的列表的情况下实现这一点,并返回分数的提高(如果有的话)和为达到该分数要移除的最佳模型。

# perform a single round of pruning the ensemble
def prune_round(models_in, X, y):
	# establish a baseline
	baseline = evaluate_ensemble(models_in, X, y)
	best_score, removed = baseline, None
	# enumerate removing each candidate and see if we can improve performance
	for m in models_in:
		# copy the list of chosen models
		dup = models_in.copy()
		# remove this model
		dup.remove(m)
		# evaluate new ensemble
		result = evaluate_ensemble(dup, X, y)
		# check for new best
		if result > best_score:
			# store the new best
			best_score, removed = result, m
	return best_score, removed

接下来,我们需要推动修剪过程。

这包括运行一轮修剪,直到通过重复调用修剪 _round() 函数无法进一步提高准确率。

如果函数为要移除的模型返回 None,我们知道没有单一的贪婪改进是可能的,我们可以返回模型的最终列表。否则,从集合中移除所选模型,并且该过程继续。

下面的*修剪 _ 集成()*函数实现了这一点,并返回最终集成中使用的模型以及通过我们的评估过程获得的分数。

# prune an ensemble from scratch
def prune_ensemble(models, X, y):
	best_score = 0.0
	# prune ensemble until no further improvement
	while True:
		# remove one model to the ensemble
		score, removed = prune_round(models, X, y)
		# check for no improvement
		if removed is None:
			print('>no further improvement')
			break
		# keep track of best score
		best_score = score
		# remove model from the list
		models.remove(removed)
		# report results along the way
		print('>%.3f (removed: %s)' % (score, removed[0]))
	return best_score, models

我们可以将所有这些结合到一个综合二进制类别数据集上的集成修剪示例中。

# example of ensemble pruning for classification
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import VotingClassifier
from matplotlib import pyplot

# get the dataset
def get_dataset():
	X, y = make_classification(n_samples=5000, n_features=20, n_informative=10, n_redundant=10, random_state=1)
	return X, y

# get a list of models to evaluate
def get_models():
	models = list()
	models.append(('lr', LogisticRegression()))
	models.append(('knn', KNeighborsClassifier()))
	models.append(('tree', DecisionTreeClassifier()))
	models.append(('nb', GaussianNB()))
	models.append(('svm', SVC(probability=True)))
	return models

# evaluate a list of models
def evaluate_ensemble(models, X, y):
	# check for no models
	if len(models) == 0:
		return 0.0
	# create the ensemble
	ensemble = VotingClassifier(estimators=models, voting='soft')
	# define the evaluation procedure
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	# evaluate the ensemble
	scores = cross_val_score(ensemble, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	# return mean score
	return mean(scores)

# perform a single round of pruning the ensemble
def prune_round(models_in, X, y):
	# establish a baseline
	baseline = evaluate_ensemble(models_in, X, y)
	best_score, removed = baseline, None
	# enumerate removing each candidate and see if we can improve performance
	for m in models_in:
		# copy the list of chosen models
		dup = models_in.copy()
		# remove this model
		dup.remove(m)
		# evaluate new ensemble
		result = evaluate_ensemble(dup, X, y)
		# check for new best
		if result > best_score:
			# store the new best
			best_score, removed = result, m
	return best_score, removed

# prune an ensemble from scratch
def prune_ensemble(models, X, y):
	best_score = 0.0
	# prune ensemble until no further improvement
	while True:
		# remove one model to the ensemble
		score, removed = prune_round(models, X, y)
		# check for no improvement
		if removed is None:
			print('>no further improvement')
			break
		# keep track of best score
		best_score = score
		# remove model from the list
		models.remove(removed)
		# report results along the way
		print('>%.3f (removed: %s)' % (score, removed[0]))
	return best_score, models

# define dataset
X, y = get_dataset()
# get the models to evaluate
models = get_models()
# prune the ensemble
score, model_list = prune_ensemble(models, X, y)
names = ','.join([n for n,_ in model_list])
print('Models: %s' % names)
print('Final Mean Accuracy: %.3f' % score)

运行该示例会执行集成修剪过程,报告每轮移除了哪个模型,以及移除模型后模型的准确性。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到执行了三轮修剪,删除了朴素贝叶斯、决策树和逻辑回归算法,只剩下平均分类准确率约为 95.7%的 SVM 和 KNN 算法。这比 SVM 和 KNN 单独使用时达到的 95.3%要好得多,也明显比将所有型号组合在一起要好。

模型的最终列表然后可以通过“估计器”参数用于新的最终投票集合模型,适合整个数据集并用于对新数据进行预测。

>0.939 (removed: nb)
>0.948 (removed: tree)
>0.957 (removed: lr)
>no further improvement
Models: knn,svm
Final Mean Accuracy: 0.957

现在我们已经熟悉了开发和评估集成修剪方法,让我们来看看扩展集成成员的相反情况。

集合增长示例

在这一节中,我们将探索如何从零开始开发一个贪婪的集成增长算法。

贪婪地发展一个集成团的结构很像贪婪地修剪成员,尽管是相反的。我们从没有模型的集合开始,添加一个表现最好的模型。然后,只有当模型在添加之前导致整体表现提升时,才会逐个添加模型。

大部分代码与剪枝情况相同,因此我们可以关注差异。

首先,我们必须定义一个函数来执行一轮集合增长。这包括列举所有可以添加的候选模型,并评估依次添加每个模型到集合中的效果。导致最大改进的单个模型随后由函数返回,同时返回它的得分。

下面的 grow_round() 函数实现了这个行为。

# perform a single round of growing the ensemble
def grow_round(models_in, models_candidate, X, y):
	# establish a baseline
	baseline = evaluate_ensemble(models_in, X, y)
	best_score, addition = baseline, None
	# enumerate adding each candidate and see if we can improve performance
	for m in models_candidate:
		# copy the list of chosen models
		dup = models_in.copy()
		# add the candidate
		dup.append(m)
		# evaluate new ensemble
		result = evaluate_ensemble(dup, X, y)
		# check for new best
		if result > best_score:
			# store the new best
			best_score, addition = result, m
	return best_score, addition

接下来,我们需要一个函数来驱动生长过程。

这涉及到一个循环,它运行一轮又一轮的增长,直到没有进一步的增加导致模型表现的提高。对于可以进行的每个添加,集合中的主要模型列表被更新,并且当前在集合中的模型列表与表现一起被报告。

*grow _ 集成()*函数实现了这一点,并返回模型列表,这些模型被贪婪地确定为产生最佳表现以及预期的平均准确率。

# grow an ensemble from scratch
def grow_ensemble(models, X, y):
	best_score, best_list = 0.0, list()
	# grow ensemble until no further improvement
	while True:
		# add one model to the ensemble
		score, addition = grow_round(best_list, models, X, y)
		# check for no improvement
		if addition is None:
			print('>no further improvement')
			break
		# keep track of best score
		best_score = score
		# remove new model from the list of candidates
		models.remove(addition)
		# add new model to the list of models in the ensemble
		best_list.append(addition)
		# report results along the way
		names = ','.join([n for n,_ in best_list])
		print('>%.3f (%s)' % (score, names))
	return best_score, best_list

将这些联系在一起,下面列出了在合成二进制类别数据集上增长的贪婪集成的完整示例。

# example of ensemble growing for classification
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import VotingClassifier
from matplotlib import pyplot

# get the dataset
def get_dataset():
	X, y = make_classification(n_samples=5000, n_features=20, n_informative=10, n_redundant=10, random_state=1)
	return X, y

# get a list of models to evaluate
def get_models():
	models = list()
	models.append(('lr', LogisticRegression()))
	models.append(('knn', KNeighborsClassifier()))
	models.append(('tree', DecisionTreeClassifier()))
	models.append(('nb', GaussianNB()))
	models.append(('svm', SVC(probability=True)))
	return models

# evaluate a list of models
def evaluate_ensemble(models, X, y):
	# check for no models
	if len(models) == 0:
		return 0.0
	# create the ensemble
	ensemble = VotingClassifier(estimators=models, voting='soft')
	# define the evaluation procedure
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	# evaluate the ensemble
	scores = cross_val_score(ensemble, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	# return mean score
	return mean(scores)

# perform a single round of growing the ensemble
def grow_round(models_in, models_candidate, X, y):
	# establish a baseline
	baseline = evaluate_ensemble(models_in, X, y)
	best_score, addition = baseline, None
	# enumerate adding each candidate and see if we can improve performance
	for m in models_candidate:
		# copy the list of chosen models
		dup = models_in.copy()
		# add the candidate
		dup.append(m)
		# evaluate new ensemble
		result = evaluate_ensemble(dup, X, y)
		# check for new best
		if result > best_score:
			# store the new best
			best_score, addition = result, m
	return best_score, addition

# grow an ensemble from scratch
def grow_ensemble(models, X, y):
	best_score, best_list = 0.0, list()
	# grow ensemble until no further improvement
	while True:
		# add one model to the ensemble
		score, addition = grow_round(best_list, models, X, y)
		# check for no improvement
		if addition is None:
			print('>no further improvement')
			break
		# keep track of best score
		best_score = score
		# remove new model from the list of candidates
		models.remove(addition)
		# add new model to the list of models in the ensemble
		best_list.append(addition)
		# report results along the way
		names = ','.join([n for n,_ in best_list])
		print('>%.3f (%s)' % (score, names))
	return best_score, best_list

# define dataset
X, y = get_dataset()
# get the models to evaluate
models = get_models()
# grow the ensemble
score, model_list = grow_ensemble(models, X, y)
names = ','.join([n for n,_ in model_list])
print('Models: %s' % names)
print('Final Mean Accuracy: %.3f' % score)

运行该示例一次递增地向集合添加一个模型,并报告模型集合的平均分类准确率。

:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到,集成增长找到了与贪婪集成修剪相同的解决方案,其中 SVM 和 KNN 的集成实现了大约 95.6%的平均分类准确率,比任何单个独立模型和组合所有模型都有所提高。

>0.953 (svm)
>0.956 (svm,knn)
>no further improvement
Models: svm,knn
Final Mean Accuracy: 0.956

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

教程

蜜蜂

摘要

在本教程中,您发现了如何从零开始开发集成选择算法。

具体来说,您了解到:

  • 集成选择包括选择集成成员的子集,这导致比使用所有成员更低的复杂性,有时还会带来更好的表现。
  • 如何开发和评估贪婪集成剪枝分类算法?
  • 如何开发和评估一个算法贪婪地从零开始增长一个集合。

你有什么问题吗? 在下面的评论中提问,我会尽力回答。