大家好,我是Sonhhxg_柒,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流
个人主页-Sonhhxg_柒的博客_CSDN博客
欢迎各位→点赞 + 收藏⭐️ + 留言
系列专栏 - 机器学习【ML】 自然语言处理【NLP】 深度学习【DL】
foreword
✔说明⇢本人讲解主要包括Python、机器学习(ML)、深度学习(DL)、自然语言处理(NLP)等内容。
如果你对这个系列感兴趣的话,可以关注订阅哟
认为你向成千上万的随机人提出一个复杂的问题,然后汇总他们的答案。在许多情况下,您会发现这个汇总的答案比专家的答案更好。这叫做群众的智慧。同样,如果您聚合一组预测变量(例如分类器或回归变量)的预测,您通常会得到比使用最佳单个预测变量更好的预测。一个一组预测变量称为一个集合;因此,这种技术被称为集成学习和集成学习算法称为Ensemble 方法。
作为一个集成方法的示例,您可以训练一组决策树分类器,每个分类器在训练集的不同随机子集上。要进行预测,您需要获得所有单个树的预测,然后预测获得最多票的类别(参见第 6 章的最后一个练习)。这样的决策树集合被称为随机森林,尽管它很简单,但它是当今可用的最强大的机器学习算法之一。
正如第 2 章所讨论的,一旦你已经构建了一些好的预测器,你会经常在项目快结束时使用 Ensemble 方法,将它们组合成一个更好的预测器。事实上,机器学习竞赛中的获胜解决方案通常涉及几种 Ensemble 方法(最著名的是在Netflix Prize 竞赛中)。
在本章中,我们将讨论最流行的 Ensemble 方法,包括bagging、boosting和stacking。我们还将探索随机森林。
认为你已经训练了几个分类器,每个分类器都达到了大约 80% 的准确率。你可能有一个逻辑回归分类器、一个 SVM 分类器、一个随机森林分类器、一个 K-最近邻分类器,也许还有更多(见图 7-1)。
图 7-1。训练不同的分类器
创建一个更好的分类器的一个非常简单的方法是聚合每个分类器的预测并预测获得最多选票的类。这个多数投票分类器称为硬投票分类器(见图 7-2)。
图 7-2。硬投票分类器预测
有点令人惊讶的是,这个投票分类器通常比集成中最好的分类器。事实上,即使每个分类器都是弱学习器(意味着它只比随机猜测好一点),只要有足够数量的弱学习器并且它们足够各种各样的。
这怎么可能?下面的类比可以帮助阐明这个谜团。假设你有一枚略微偏向的硬币,正面朝上的概率为 51%,反面朝上的概率为 49%。如果你扔它 1000 次,你通常会得到或多或少的 510 个正面和 490 个反面,因此大多数正面。如果你算一算,你会发现在 1000 次投掷后获得多数正面的概率接近 75%。抛硬币越多,概率就越高(例如,抛 10,000 次,概率上升 97% 以上)。这个这是由于大数定律:随着你不断抛硬币,正面的比例越来越接近正面的概率(51%)。图 7-3显示了 10 组有偏差的抛硬币。可以看到,随着投掷次数的增加,正面的比例接近 51%。最终,所有 10 个系列最终都接近 51%,以至于它们始终高于 50%。
图 7-3。大数定律
类似地,假设您构建了一个包含 1,000 个分类器的集合,这些分类器的正确率只有 51%(几乎不比随机猜测好)。如果您预测多数投票类别,则可以期望高达 75% 的准确率!但是,只有当所有分类器完全独立时才会出现这种情况,从而产生不相关的错误,显然情况并非如此,因为它们是在相同的数据上训练的。他们很可能会犯相同类型的错误,因此会有很多多数票支持错误的类别,从而降低了集成的准确性。
小费
集成方法当预测变量尽可能相互独立时效果最好。获得多样化分类器的一种方法是使用非常不同的算法来训练它们。这增加了他们犯不同类型错误的机会,从而提高了整体的准确性。
这以下代码在 Scikit-Learn 中创建并训练了一个投票分类器,由三个不同的分类器组成(训练集是卫星数据集,在第 5 章中介绍):
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import VotingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
log_clf = LogisticRegression()
rnd_clf = RandomForestClassifier()
svm_clf = SVC()
voting_clf = VotingClassifier(
estimators=[('lr', log_clf), ('rf', rnd_clf), ('svc', svm_clf)],
voting='hard')
voting_clf.fit(X_train, y_train)
让我们看看每个分类器在测试集上的准确率:
>>> from sklearn.metrics import accuracy_score
>>> for clf in (log_clf, rnd_clf, svm_clf, voting_clf):
... clf.fit(X_train, y_train)
... y_pred = clf.predict(X_test)
... print(clf.__class__.__name__, accuracy_score(y_test, y_pred))
...
LogisticRegression 0.864
RandomForestClassifier 0.896
SVC 0.888
VotingClassifier 0.904
你有它!投票分类器稍微优于所有单个分类器。
如果所有分类器都能够估计类概率(即,它们都有一个predict_proba()
方法),然后您可以告诉 Scikit-Learn 预测具有最高类概率的类,对所有单独的分类器进行平均。这称为软投票。它通常比硬投票获得更高的性能,因为它赋予高度自信的投票更多的权重。您需要做的就是替换voting="hard"
并voting="soft"
确保所有分类器都可以估计类概率。默认情况下该类不是这种情况SVC
,因此您需要将其probability
超参数设置为True
(这将使SVC
该类使用交叉验证来估计类概率,减慢训练速度,并且它会添加一个predict_proba()
方法)。如果修改前面的代码使用软投票,你会发现投票分类器的准确率达到了 91.2% 以上!
一如前所述,获得一组多样化分类器的方法是使用非常不同的训练算法。另一种方法是对每个预测器使用相同的训练算法,并在训练集的不同随机子集上训练它们。当进行带放回抽样时,这种方法称为bagging 1(bootstrap agregating 2的缩写)。当不替换地进行采样时,称为粘贴。3
换句话说,bagging 和 paste 都允许跨多个预测器对训练实例进行多次采样,但只有 bagging 允许对同一预测器对训练实例进行多次采样。图 7-4表示了这种抽样和训练过程。
一旦所有的预测器都经过训练,集成可以通过简单地聚合所有预测器的预测来对新实例进行预测。聚合函数是通常是用于分类的统计模式(即最频繁的预测,就像硬投票分类器),或用于回归的平均值。与在原始训练集上训练相比,每个单独的预测器具有更高的偏差,但聚合减少了偏差和方差。4通常,最终结果是与在原始训练集上训练的单个预测器相比,集成具有相似的偏差但方差更低。
如图7-4 所示,预测器都可以通过不同的 CPU 内核甚至不同的服务器并行训练。类似地,预测可以并行进行。这是装袋和粘贴方法如此流行的原因之一:它们的扩展性非常好。
Scikit-学习提供了一个简单的 API,用于对BaggingClassifier
类进行装袋和粘贴(或BaggingRegressor
用于回归)。以下代码训练了500个决策树分类器的集合:每个分类器都在 100 个训练实例上进行训练,这些实例是从训练集中随机抽样并替换的(这是 bagging 的一个示例,但如果您想使用粘贴代替,只需 set bootstrap=False
)。该n_jobs
参数告诉 Scikit-Learn 用于训练和预测的 CPU 内核数量(–1
告诉 Scikit-Learn 使用所有可用的内核):
from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
bag_clf = BaggingClassifier(
DecisionTreeClassifier(), n_estimators=500,
max_samples=100, bootstrap=True, n_jobs=-1)
bag_clf.fit(X_train, y_train)
y_pred = bag_clf.predict(X_test)
笔记
如果
BaggingClassifier
基分类器可以估计类概率(即,如果它有predict_proba()
方法),则自动执行软投票而不是硬投票,决策树分类器就是这种情况。
图 7-5将单个决策树的决策边界与 500 棵树(来自前面的代码)的 bagging 集成的决策边界进行了比较,两者都在卫星数据集上进行了训练。如您所见,集成的预测可能会比单个决策树的预测更好地概括:集成具有可比较的偏差但方差较小(它在训练集上产生大致相同数量的错误,但决策边界更少不规律的)。
图 7-5。单个决策树(左)与 500 棵树的 bagging 集成(右)
Bootstrapping 在训练每个预测器的子集中引入了更多的多样性,因此 bagging 的偏差比粘贴略高;但额外的多样性也意味着预测变量最终的相关性降低,因此集合的方差减少了。总体而言,bagging 通常会产生更好的模型,这解释了为什么它通常是首选。但是,如果您有空闲时间和 CPU 能力,您可以使用交叉验证来评估 bagging 和 paste 并选择效果最好的一个。
和bagging,对于任何给定的预测器,某些实例可能会被采样多次,而其他实例可能根本不会被采样。默认情况下,aBaggingClassifier
样本m个带有替换 ( bootstrap=True
) 的训练实例,其中m是训练集的大小。这意味着对于每个预测变量,平均只有大约 63% 的训练实例被采样。6其余 37% 的未采样的训练实例称为袋外(oob) 实例。请注意,对于所有预测变量,它们不是相同的 37%。
Bagging ensemble 可以使用 oob 实例进行评估,而不需要单独的验证集:确实,如果有足够的估计器,那么训练集中的每个实例都可能是多个估计器的 oob 实例,因此可以使用这些估计器为该实例做出公平的集成预测。一旦您对每个实例进行了预测,您就可以计算集成的预测准确度(或任何其他指标)。
在 Scikit-Learn 中,您可以oob_score=True
在创建时设置BaggingClassifier
以在训练后请求自动 oob 评估。下面的代码演示了这一点。由此产生的评估分数可通过oob_score_
变量获得:
>>> bag_clf = BaggingClassifier(
... DecisionTreeClassifier(), n_estimators=500,
... bootstrap=True, n_jobs=-1, oob_score=True)
...
>>> bag_clf.fit(X_train, y_train)
>>> bag_clf.oob_score_
0.90133333333333332
根据这个 oob 评估,这BaggingClassifier
很可能在测试集上达到 90.1% 左右的准确率。让我们验证一下:
>>> from sklearn.metrics import accuracy_score
>>> y_pred = bag_clf.predict(X_test)
>>> accuracy_score(y_test, y_pred)
0.91200000000000003
我们在测试集上获得了 91.2% 的准确率——足够接近了!
每个训练实例的 oob 决策函数也可以通过oob_decision_function_
变量获得。在这种情况下(因为基础估计器有一个predict_proba()
方法),决策函数返回每个训练实例的类概率。例如,oob 评估估计第一个训练实例有 68.25% 的概率属于正类(以及 31.75% 的属于负类):
>>> bag_clf.oob_decision_function_
array([[0.31746032, 0.68253968],
[0.34117647, 0.65882353],
[1. , 0. ],
...
[1. , 0. ],
[0.03108808, 0.96891192],
[0.57291667, 0.42708333]])
BaggingClassifier
班级_也支持对特征进行采样。采样由两个超参数控制:max_features
和bootstrap_features
。它们的工作方式与max_samples
和相同bootstrap
,但用于特征采样而不是实例采样。因此,每个预测器都将在输入特征的随机子集上进行训练。
当您处理高维输入(例如图像)时,此技术特别有用。对训练实例和特征进行采样称为Random Patches方法。7保留所有训练实例(通过设置bootstrap=False
和max_samples=1.0
)但采样特征(通过设置bootstrap_features
和True
/或max_features
小于 的值1.0
)称为随机子空间方法。8
抽样特征会导致更多的预测变量,用更多的偏差换取更低的方差。
正如我们所拥有的讨论过,随机森林9是决策树的集合,通常通过装袋方法(或有时粘贴)进行训练,通常max_samples
设置为训练集的大小。您可以使用类来代替构建 aBaggingClassifier
并将其传递给它,该类更方便且针对决策树10进行了优化(类似地,有一个用于回归任务的类)。以下代码使用所有可用的 CPU 内核来训练具有 500 棵树(每棵树最多 16 个节点)的随机森林分类器:DecisionTreeClassifier
RandomForestClassifier
RandomForestRegressor
from sklearn.ensemble import RandomForestClassifier
rnd_clf = RandomForestClassifier(n_estimators=500, max_leaf_nodes=16, n_jobs=-1)
rnd_clf.fit(X_train, y_train)
y_pred_rf = rnd_clf.predict(X_test)
除了少数例外,一个RandomForestClassifier
具有 一个的所有超参数DecisionTreeClassifier
(用于控制树的生长方式),以及BaggingClassifier
用于控制集成本身的 a 的所有超参数。11
随机森林算法在种植树木时引入了额外的随机性;它不是在分割节点时搜索最佳特征(参见第 6 章),而是在随机特征子集中搜索最佳特征。该算法导致更大的树多样性,这(再次)用更高的偏差换取更低的方差,通常会产生整体更好的模型。以下BaggingClassifier
等价于前面的RandomForestClassifier
:
bag_clf = BaggingClassifier(
DecisionTreeClassifier(max_features="auto", max_leaf_nodes=16),
n_estimators=500, max_samples=1.0, bootstrap=True, n_jobs=-1)
什么时候您正在随机森林中种植一棵树,在每个节点处,仅考虑将特征的随机子集进行拆分(如前所述)。通过为每个特征使用随机阈值而不是搜索可能的最佳阈值(就像常规决策树所做的那样),可以使树更加随机。
一个这种极其随机的树的森林称为Extremely Randomized Trees ensemble 12(或简称Extra-Trees)。再一次,这种技术用更多的偏差换取了更低的方差。它还使 Extra-Trees 的训练速度比常规随机森林快得多,因为在每个节点上为每个特征找到可能的最佳阈值是生长树最耗时的任务之一。
你可以使用 Scikit-Learn 的ExtraTreesClassifier
类创建一个 Extra-Trees 分类器。它的 API 与RandomForestClassifier
类相同。同样,ExtraTreesRegressor
该类具有与该类相同的 API RandomForestRegressor
。
小费
很难提前判断 a
RandomForestClassifier
会比 a 表现更好还是更差ExtraTreesClassifier
。通常,唯一知道的方法是尝试两者并使用交叉验证(使用网格搜索调整超参数)进行比较。
然而随机森林的另一个优点是它们可以很容易地衡量每个特征的相对重要性。Scikit-学习通过查看使用该特征的树节点平均减少了多少杂质(在森林中的所有树上)来衡量特征的重要性。更准确地说,它是一个加权平均值,其中每个节点的权重等于与其关联的训练样本的数量(参见第 6 章)。
Scikit-Learn 在训练后自动为每个特征计算这个分数,然后缩放结果,使所有重要性的总和等于 1。您可以使用feature_importances_
变量访问结果。例如,以下代码RandomForestClassifier
在 iris 数据集(第 4 章介绍)上训练 a 并输出每个特征的重要性。似乎最重要的特征是花瓣长度(44%)和宽度(42%),而相比之下,萼片长度和宽度并不重要(分别为 11% 和 2%):
>>> from sklearn.datasets import load_iris
>>> iris = load_iris()
>>> rnd_clf = RandomForestClassifier(n_estimators=500, n_jobs=-1)
>>> rnd_clf.fit(iris["data"], iris["target"])
>>> for name, score in zip(iris["feature_names"], rnd_clf.feature_importances_):
... print(name, score)
...
sepal length (cm) 0.112492250999
sepal width (cm) 0.0231192882825
petal length (cm) 0.441030464364
petal width (cm) 0.423357996355
类似地,如果你在 MNIST 数据集(第 3 章介绍)上训练一个随机森林分类器并绘制每个像素的重要性,你会得到如图 7-6 所示的图像。
图 7-6。MNIST 像素重要性(根据随机森林分类器)
随机森林非常方便快速了解哪些特征真正重要,尤其是在您需要执行特征选择时。
Boosting(原称hypothesis boosting)是指任何可以将几个弱学习器组合成一个强学习器的集成方法。大多数提升方法的总体思路是按顺序训练预测器,每个预测器都试图纠正它的前任。有许多提升方法可用,但目前最流行的是AdaBoost 13(Adaptive Boosting的缩写)和梯度提升。让我们从 AdaBoost 开始。
一新预测器纠正其前任的方法是更多地关注前任欠拟合的训练实例。这导致新的预测器越来越关注困难的情况。这是AdaBoost使用的技术。
例如,当训练一个AdaBoost 分类器,该算法首先训练一个基分类器(例如决策树)并使用它对训练集进行预测。然后,该算法会增加错误分类的训练实例的相对权重。然后它使用更新后的权重训练第二个分类器,再次对训练集进行预测,更新实例权重,等等(见图 7-7)。
图 7-7。使用实例权重更新的 AdaBoost 顺序训练
图 7-8显示了卫星数据集上五个连续预测器的决策边界(在此示例中,每个预测器都是具有 RBF 内核的高度正则化的 SVM 分类器14)。第一个分类器得到了许多错误的实例,因此它们的权重得到了提升。因此,第二个分类器在这些实例上做得更好,依此类推。右侧的图表示相同的预测变量序列,除了学习率减半(即,错误分类的实例权重在每次迭代中提升的幅度要小得多)。如您所见,这种顺序学习技术与梯度下降有一些相似之处,除了调整单个预测器的参数以最小化成本函数之外,AdaBoost 将预测器添加到集成中,逐渐使其变得更好。
图 7-8。连续预测变量的决策边界
一旦所有的预测器都被训练好了,集成进行预测就像装袋或粘贴一样,除了预测器有不同的权重,这取决于它们在加权训练集上的整体准确性。
警告
这种顺序学习技术有一个重要缺点:它不能并行化(或仅部分并行化),因为每个预测器只能在前一个预测器经过训练和评估之后才能被训练。因此,它不会像装袋或粘贴那样缩放。
让我们仔细看看 AdaBoost 算法。每个实例权重w ( i )最初设置为 1/ m。训练第一个预测器,并在训练集上计算其加权错误率r1;见公式 7-1。
然后使用公式 7-2计算预测变量的权重α j,其中η是学习率超参数(默认为 1)。15预测器越准确,其权重就越高。如果它只是随机猜测,那么它的权重将接近于零。然而,如果它经常是错误的(即,不如随机猜测准确),那么它的权重就是负数。
接下来,AdaBoost 算法使用公式 7-3更新实例权重,从而提高错误分类实例的权重。
公式 7-3。权重更新规则
最后,使用更新后的权重训练一个新的预测器,并重复整个过程(计算新预测器的权重,更新实例权重,然后训练另一个预测器,等等)。当达到所需的预测器数量或找到完美的预测器时,算法停止。
为了进行预测,AdaBoost 简单地计算所有预测器的预测并使用预测器权重α j对它们进行加权。预测的类别是获得大多数加权投票的类别(请参见公式 7-4)。
Scikit-学习使用 AdaBoost 的多类版本,称为SAMME 16(代表Stagewise Additive Modeling using a Multiclass Exponential loss function)。当只有两个类时,SAMME 相当于 AdaBoost。如果预测器可以估计类概率(即,如果它们有predict_proba()
方法),Scikit-Learn 可以使用称为SAMME.R(R代表“真实”)的 SAMME 变体,它依赖于类概率而不是预测,并且通常表现更好。
这以下代码使用 Scikit-Learn 的类训练基于 200 个决策树桩AdaBoostClassifier
的 AdaBoost 分类器(如您所料,还有一个AdaBoostRegressor
类)。决策树桩是一棵决策树,max_depth=1
换句话说,一棵树由一个决策节点加上两个叶节点组成。这是AdaBoostClassifier
该类的默认基本估计器:
from sklearn.ensemble import AdaBoostClassifier
ada_clf = AdaBoostClassifier(
DecisionTreeClassifier(max_depth=1), n_estimators=200,
algorithm="SAMME.R", learning_rate=0.5)
ada_clf.fit(X_train, y_train)
小费
如果您的 AdaBoost 集成过度拟合训练集,您可以尝试减少估计器的数量或更强烈地正则化基本估计器。
其他非常流行的提升算法是梯度提升。17就像 AdaBoost 一样,梯度提升的工作原理是按顺序将预测变量添加到一个集成中,每个预测变量都会纠正其前身。然而,这种方法不是像 AdaBoost 那样在每次迭代中调整实例权重,而是尝试拟合新的预测器到前一个预测器产生的残差。
让我们通过一个简单的回归示例,使用决策树作为基本预测变量(当然,梯度提升也适用于回归任务)。这称为梯度树提升或梯度提升回归树(GBRT)。首先,让我们将 a 拟合DecisionTreeRegressor
到训练集(例如,嘈杂的二次训练集):
from sklearn.tree import DecisionTreeRegressor
tree_reg1 = DecisionTreeRegressor(max_depth=2)
tree_reg1.fit(X, y)
接下来,我们将对DecisionTreeRegressor
第一个预测器产生的残差进行第二次训练:
y2 = y - tree_reg1.predict(X)
tree_reg2 = DecisionTreeRegressor(max_depth=2)
tree_reg2.fit(X, y2)
然后我们根据第二个预测器的残差训练第三个回归器:
y3 = y2 - tree_reg2.predict(X)
tree_reg3 = DecisionTreeRegressor(max_depth=2)
tree_reg3.fit(X, y3)
现在我们有一个包含三棵树的集合。它可以简单地通过将所有树的预测相加来对新实例进行预测:
y_pred = sum(tree.predict(X_new) for tree in (tree_reg1, tree_reg2, tree_reg3))
图 7-9左列表示这三棵树的预测,右列表示集成的预测。在第一行,集成只有一棵树,因此它的预测与第一棵树的预测完全相同。在第二行中,根据第一棵树的残差训练一棵新树。在右侧,您可以看到集成的预测等于前两棵树的预测之和。类似地,在第三行中,另一棵树根据第二棵树的残差进行训练。您可以看到,随着将树添加到集成中,集成的预测逐渐变得更好。
一个训练 GBRT 集成的更简单方法是使用 Scikit-Learn 的GradientBoostingRegressor
课程。与该类非常相似RandomForestRegressor
,它具有控制决策树生长的超参数(例如 ,max_depth
)min_samples_leaf
,以及控制集成训练的超参数,例如树的数量(n_estimators
)。以下代码创建与前一个相同的集合:
from sklearn.ensemble import GradientBoostingRegressor
gbrt = GradientBoostingRegressor(max_depth=2, n_estimators=3, learning_rate=1.0)
gbrt.fit(X, y)
超learning_rate
参数缩放每棵树的贡献。如果您将其设置为较低的值,例如0.1
,您将需要集成中更多的树来拟合训练集,但预测通常会更好地泛化。这个是一种称为收缩的正则化技术。图 7-10显示了两个以低学习率训练的 GBRT 集成:左边的一个没有足够的树来适应训练集,而右边的一个有太多的树并且过拟合了训练集。
图 7-10。预测变量不足(左)和太多(右)的 GBRT 集成
为了找到最佳的树数,您可以使用提前停止(参见第 4 章)。实现这一点的一种简单方法是使用该staged_predict()
方法:它返回一个迭代器,该迭代器在训练的每个阶段(使用一棵树、两棵树等)由集成所做的预测返回。以下代码用 120 棵树训练一个 GBRT 集成,然后测量每个训练阶段的验证误差以找到最佳树数,最后使用最佳树数训练另一个 GBRT 集成:
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
X_train, X_val, y_train, y_val = train_test_split(X, y)
gbrt = GradientBoostingRegressor(max_depth=2, n_estimators=120)
gbrt.fit(X_train, y_train)
errors = [mean_squared_error(y_val, y_pred)
for y_pred in gbrt.staged_predict(X_val)]
bst_n_estimators = np.argmin(errors) + 1
gbrt_best = GradientBoostingRegressor(max_depth=2,n_estimators=bst_n_estimators)
gbrt_best.fit(X_train, y_train)
验证错误在图 7-11的左侧表示,最佳模型的预测在右侧表示。
图 7-11。使用提前停止调整树的数量
也可以通过实际提前停止训练来实现提前停止(而不是先训练大量树,然后再回头寻找最佳数量)。您可以通过设置来做到warm_start=True
这一点,这使得 Scikit-Learnfit()
调用该方法时保留现有树,允许增量训练。当验证错误连续五次迭代没有改善时,以下代码停止训练:
gbrt = GradientBoostingRegressor(max_depth=2, warm_start=True)
min_val_error = float("inf")
error_going_up = 0
for n_estimators in range(1, 120):
gbrt.n_estimators = n_estimators
gbrt.fit(X_train, y_train)
y_pred = gbrt.predict(X_val)
val_error = mean_squared_error(y_val, y_pred)
if val_error < min_val_error:
min_val_error = val_error
error_going_up = 0
else:
error_going_up += 1
if error_going_up == 5:
break # early stopping
该类GradientBoostingRegressor
还支持一个subsample
超参数,它指定用于训练每棵树的训练实例的比例。例如,如果subsample=0.25
,则每棵树都在随机选择的 25% 的训练实例上进行训练。您现在可能已经猜到了,这种技术以较高的偏差换取较低的方差。它还大大加快了训练速度。这个称为随机梯度提升。
笔记
可以将梯度提升与其他成本函数一起使用。这由
loss
超参数控制(有关更多详细信息,请参阅 Scikit-Learn 的文档)。
它值得注意的是,流行的 Python 库XGBoost中提供了 Gradient Boosting 的优化实现,它代表 Extreme Gradient Boosting。该软件包最初由 Tianqi Chen 作为分布式(深度)机器学习社区 (DMLC) 的一部分开发,旨在实现极快、可扩展和便携。事实上,XGBoost 往往是 ML 比赛中获奖作品的重要组成部分。XGBoost 的 API 与 Scikit-Learn 的非常相似:
import xgboost
xgb_reg = xgboost.XGBRegressor()
xgb_reg.fit(X_train, y_train)
y_pred = xgb_reg.predict(X_val)
XGBoost 还提供了一些不错的功能,例如自动处理提前停止:
xgb_reg.fit(X_train, y_train,
eval_set=[(X_val, y_val)], early_stopping_rounds=2)
y_pred = xgb_reg.predict(X_val)
你一定要检查一下!
这我们将在本章中讨论的最后一个集成方法称为堆叠(stacking generalization的缩写)。18它基于一个简单的想法:我们为什么不训练一个模型来执行这种聚合,而不是使用琐碎的函数(例如硬投票)来聚合一个集成中所有预测器的预测?图 7-12显示了这样一个在新实例上执行回归任务的集成。底部三个预测变量中的每一个预测一个不同的值(3.1、2.7 和 2.9),然后是最终预测变量(称为混合器或元学习器)将这些预测作为输入并进行最终预测(3.0)。
图 7-12。使用混合预测器聚合预测
为了训练搅拌机,一种常见的方法是使用保持集。19让我们看看它是如何工作的。首先,训练集被分成两个子集。第一个子集用于训练第一层的预测器(见图 7-13)。
图 7-13。训练第一层
接下来,第一层的预测器用于对第二个(保留的)集合进行预测(见图 7-14)。这确保了预测是“干净的”,因为预测器在训练期间从未见过这些实例。对于保留集中的每个实例,都有三个预测值。我们可以使用这些预测值作为输入特征创建一个新的训练集(这使得这个新的训练集是 3D 的),并保持目标值。混合器在这个新的训练集上进行训练,因此它学习预测目标值,给定第一层的预测。
实际上可以通过这种方式训练几个不同的混合器(例如,一个使用线性回归,另一个使用随机森林回归),以获得一整层混合器。诀窍是将训练集分成三个子集:第一个用于训练第一层,第二个用于创建用于训练第二层的训练集(使用第一层的预测器做出的预测) ),第三个用于创建训练集以训练第三层(使用第二层的预测器做出的预测)。完成后,我们可以通过依次遍历每一层来对新实例进行预测,如图 7-15所示。
图 7-15。多层堆叠系综中的预测
不幸的是,Scikit-Learn 不支持直接堆叠,但推出自己的实现并不难(参见以下练习)。或者,您可以使用开源实现,例如DESlib.
如果你在完全相同的训练数据上训练了五个不同的模型,并且它们都达到了 95% 的精度,那么你有没有机会将这些模型结合起来获得更好的结果?如果是这样,怎么做?如果不是,为什么?
硬投票分类器和软投票分类器有什么区别?
是否可以通过将bagging ensemble 分布在多个服务器上来加速它的训练?粘贴合奏、增强合奏、随机森林或堆叠合奏怎么样?
袋外评估有什么好处?
是什么让 Extra-Trees 比常规随机森林更随机?这种额外的随机性有什么帮助?Extra-Trees 比常规随机森林慢还是快?
如果您的 AdaBoost 集成不适合训练数据,您应该调整哪些超参数以及如何调整?
如果你的 Gradient Boosting 集成过拟合训练集,你应该增加还是减少学习率?
加载 MNIST 数据(在第 3 章中介绍),并将其拆分为训练集、验证集和测试集(例如,使用 50,000 个实例进行训练,10,000 个用于验证,10,000 个用于测试)。然后训练各种分类器,例如随机森林分类器、Extra-Trees 分类器和 SVM 分类器。接下来,尝试使用软投票或硬投票将它们组合成一个优于验证集上每个单独分类器的集成。一旦你找到了,就在测试集上试一试。与单个分类器相比,它的性能要好多少?
运行上一个练习中的各个分类器以对验证集进行预测,并使用结果预测创建一个新的训练集:每个训练实例都是一个向量,其中包含来自所有分类器对图像的预测集,目标是图像的类。在这个新的训练集上训练一个分类器。恭喜,您刚刚训练了一个搅拌机,并与分类器一起形成了一个堆叠集成!现在评估测试集上的集成。对于测试集中的每个图像,使用所有分类器进行预测,然后将预测提供给混合器以获得集成的预测。它与您之前训练的投票分类器相比如何?
附录 A中提供了这些练习的解决方案。
1Leo Breiman,“Bagging Predictors”,机器学习24,第 2 (1996): 123–140。
2在统计学中,带替换的重采样称为bootstrapping。
3Leo Breiman,“在大型数据库和在线分类中粘贴小票”,机器学习36,第 3 期。1-2 (1999): 85-103。
4第 4 章介绍了偏差和方差。
5 max_samples
也可以设置为 0.0 和 1.0 之间的浮点数,在这种情况下,要采样的最大实例数等于训练集 times 的大小max_samples
。
6随着m的增长,该比率接近 1 – exp(–1) ≈ 63.212%。
7Gilles Louppe 和 Pierre Geurts,“Ensembles on Random Patches” ,计算机科学讲义7523(2012):346–361。
8Tin Kam Ho,“构建决策森林的随机子空间方法”,IEEE Transactions on Pattern Analysis and Machine Intelligence 20,不。8 (1998): 832–844。
9Tin Kam Ho,“随机决策森林” ,第三届国际文档分析和识别会议论文集1(1995):278。
10BaggingClassifier
如果您想要一袋决策树以外的东西,该类仍然很有用。
11有一些值得注意的例外:splitter
不存在(强制执行"random"
)、presort
不存在(强制执行False
)、max_samples
不存在(强制执行1.0
)和base_estimator
不存在(强制DecisionTreeClassifier
执行提供的超参数)。
12Pierre Geurts 等人,“极度随机化的树”,机器学习63,第 1 期。1 (2006): 3-42。
13Yoav Freund 和 Robert E. Schapire,“在线学习的决策理论概括和提升的应用” ,计算机和系统科学杂志55,第 1 期。1 (1997): 119–139。
14这仅用于说明目的。SVM 通常不是 AdaBoost 的良好基础预测器;它们很慢,而且往往不稳定。
15原始的 AdaBoost 算法不使用学习率超参数。
16更多细节参见 Ji Zhu et al., “Multi-Class AdaBoost,” Statistics and Its Interface 2, no. 3 (2009): 349–360。
17Gradient Boosting 在 Leo Breiman 1997 年的论文“Arcing the Edge”中首次引入,并在Jerome H. Friedman的1999 年论文“Greedy Function Approximation: A Gradient Boosting Machine”中得到进一步发展。
18David H. Wolpert,“堆叠泛化”,神经网络5,第 5 期。2 (1992): 241–259。
19或者,可以使用折叠预测。在某些情况下,这称为堆叠,而使用保留集称为混合。对于许多人来说,这些术语是同义词。