集成学习的威力
前两个小节介绍了集成学习,集成学习的思路就是让多个机器学习算法在同一个问题上分别进行学习并预测,最终根据投票 "少数服从多数" 的原则作出最终预测。根据统计学中的大数定理可知,如果想要通过集成学习得到更可信、更好的结果,就需要上千上万甚至更多的机器学习模型(投票者)。
正因为如此,我们需要创建更多的子模型,集成更多的子模型的意见,而且更加重要的是这些子模型之间不能一致(这些一致的子模型本质为一个模型),子模型之间要有差异性。
如何才能创建出更多具有差异性的子模型呢?一个简单的方法就是每个子模型只看样本数据的一部分。 例如,一共有 500 个样本,训练的时候可以让每一个子模型只看 100 个样本,这些子模型可以使用相同的机器学习算法。虽然这些子模型使用的是相同的机器学习算法,但是由于每个子模型训练的 100 个样本是不一样的,因此训练出来的这些子模型肯定会存在一定的差异性。
显而易见,每个子模型只看其中的 100 个样本,每个子模型的准确率会变的比较低。集成学习中集成了诸多的子模型来投票,决定最终的分类结果,集成学习中的每个子模型,并不需要太高的准确率,这就是集成学习的威力所在!
为什么在集成学习中,每个子模型并不需要太高的准确率呢?下面举一个具体的例子,对于二分类问题来说,如果考虑极端情况,每个子模型只有 51% 的准确率(虽然并不需要太高的准确率,但是它的准确率至少应该要比抛一枚硬币的平均水平 50% 要高)。
- 如果只集成 1 个子模型,整体的准确率为:51%;
- 如果集成 3 个子模型,整体的准确率为:;
如果只集成 1 个子模型,整体集成学习的准确率为 51%,显然这个准确率太低了,仅比通过抛硬币来决定划分哪一类高了 1 个百分点。假设分类任务的样本数据是无偏的,如果集成 3 个子模型,根据少数服从多数的原理,最终集成学习能够预测正确,至少需要三个模型中的两个子模型预测正确。集成的 3 个子模型比集成的 1 个子模型准确率提升了 0.05%,虽然准确率的提升并不明显,但是证明了集成学习的威力。
- 如果集成 500 个子模型,整体的准确率:;
随着集成子模型数量的增加,相应的集成学习的整体准确率不断上升。 当然,实际每个子模型的准确率并不会仅比抛硬币的准确率高 1% 这样极端。假设此时每个子模型的准确率达到了 60%,集成 500 个子模型,整体的准确率:。
当然这只是一个理论的情况,通过这样的计算,可以看到集成学习的威力,集成的每个子模型不需要太高的准确率,而集成这些子模型后整体能够达到非常高的准确率。当然,在实际使用中,并不能保证每个子模型准确率都是 60%。正常的情况,子模型的准确率有高有低,甚至有些子模型的准确率达不到 50%(错误率更高)。
通过前面的例子,理解了集成学习的威力,在一般的机器学习算法比赛中集成学习的使用频率非常高,通常情况下,都能够得到非常好的结果。
Bagging 和 Pasting
前面提到每个子模型只看样本的一部分,该如何看样本数据的一部分呢?我们有两种方式:
- 放回取样,每次都从 500 个样本中取出 100 个样本
- 第一次从 500 个样本中取出 100 个样本训练第一个子模型,然后将这 100 个样本放回去;
- 第二次从 500 个样本中取出 100 个样本训练第二个子模型,然后将这 100 个样本放回去;
- 以此类推;
- 不放回取样,每次从剩下的样本中取出 100 个样本
- 第一次从 500 个样本中取出 100 个样本训练第一个子模型;
- 第二次从剩下的 400 个样本中取出 100 个样本训练第二个子模型;
- 以此类推;
在机器学习中,我们将有放回取样称为 Bagging,不放回取样称为 Pasting。Bagging 更为常用,也就是放回取样的方式,使用 Bagging 相比于 Pasting 具有以下两个优点:
- Baging 能够训练更多的子模型。假设只有 500 个样本,每次取 100 个样本训练子模型,采用无放回采样(Pasting),只能训练 5 个子模型,训练子模型的数量太少了,而如果采用有放回采样(Bagging),非常容易的训练成百上千的子模型;
- Bagging 能够消除随机性。如果使用 Pasting 不放回取样,500 个样本,每个子模型只能看到 100 个样本,其实就等同于将这 500 个样本分割成 5 份,每一份有 100 个样本,如何划分,将非常强烈的影响最终 Pasting 集成学习的结果。而 Bagging 每次都是从 500 个样本中取出 100 个样本来进行训练学习,这个学习过程,相当于重复了非常多次,在重复的过程中,其实一定程度上将这个随机过程所带来的影响给消除了;
Bagging 是机器学习领域的一个叫法,在统计学中,放回取样称为 bootstrap。在 sklearn 中控制集成学习的取样方式,到底是放回取样还是不放回取样,只需要调整一个名为 bootstrap 的参数。
使用 sklearn 实现 Bagging
导入相关的库函数。
代码语言:javascript复制import numpy as np
import matplotlib.pyplot as plt
本小节使用分布呈现交错半圆形的二分类虚拟数据集,使用 sklearn.datasets 包下的 make_moons 函数即可生成这样的虚拟数据集。
代码语言:javascript复制from sklearn import datasets
X, y = datasets.make_moons(n_samples = 500,
noise = 0.3,
random_state = 42)
在使用 make_moons 函数时指定三个参数:
- n_samples,生成样本点的总数。默认为 100 个,由于本章需要的数据量相对比较大,因此将 n_samples 设置为 500;
- noise,加到数据集中的高斯噪声的标准差。默认为 None,noise 的值越小,生成的数据集呈现交错半圆形的分布形状越明显,noise 的值越大,生成的数据集呈现交错半圆形的分布形状越不明显,此时将 noise 设置为相对比较大的 0.3;
- random_state,随机种子。设置固定的随机种子,能够保证多次试验结果的一致性;
使用散点图将生成的虚拟数据集绘制出来。
代码语言:javascript复制plt.scatter(X[y == 0, 0], X[y == 0, 1])
plt.scatter(X[y == 1, 0], X[y == 1, 1])
plt.show()
使用 train_test_split 方法将数据集划分为训练集和测试集。
代码语言:javascript复制from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state = 42)
接下来,具体的看一下,如何在 sklearn 中使用 bagging 这种方式来进行集成学习。由于 Bagging 本身是集成学习,所以需要集成很多单独的算法,接下来让 Bagging 分类器集成的算法模型都是决策树模型,使用决策树模型这种非参数学习的方式更能产生差异比较大的模型,决策树里面的很多参数,很多剪枝方式都能够使集成学习中的每一个子模型更具有差异,或者更加随机。 集成学习更喜欢这种有差异的子模型,所以通常在集成学习中,如果要集成成百上千个这种子模型的话,首选就是决策树。
使用 Bagging 这种集成学习方式,需要从 ensemble 模块中,导入 BaggingClassifier 类。
代码语言:javascript复制from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import BaggingClassifier
bagging_clf = BaggingClassifier(DecisionTreeClassifier(),
n_estimators = 500,
max_samples = 100,
bootstrap = True)
实例化 BaggingClassifier 时传入了四个参数:
- 集成的每一个模型采用的算法。此时使用决策树算法;
- n_estimators:集成子模型的个数。此时集成 500 个决策树子模型;
- max_samples:训练每个子模型的样本个数。此时为 100 个样本,即每个子模型在 100 个样本上训练;
- bootstrap:集成学习采取的是有放回还是无放回。此时为 True,即采用有放回 Bagging 的方式;
当 bootstrap 为 False 时,表示使用 Posting 的方式集成。不过在 sklearn 中,将 Bagging 和 Posting 统一封装在 BaggingClassifier 中,具体靠 boostrap 参数来决定使用 Bagging(boostrap = True)有放回还是 Posting(boostrap = False)无放回。
实例化了 BaggingClassifier 之后,可以调用 fit 方法来拟合训练集,并通过 score 方法查看使用 Bagging 方式的集成学习在测试集上的分类准确度。
代码语言:javascript复制bagging_clf.fit(X_train, y_train)
bagging_clf.score(X_test, y_test)
# 0.904
如果将这 500 个样本全部用于决策树的训练。
代码语言:javascript复制tree = DecisionTreeClassifier()
tree.fit(X_train, y_train)
tree.score(X_test, y_test)
# 0.864
显然使用有放回的集成决策树的方式要比单独使用决策树在全部样本上进行训练的准确率要高(0.904 > 0.864)。
如果将集成子模型的个数设置为 5000。
代码语言:javascript复制bagging_clf2 = BaggingClassifier(DecisionTreeClassifier(),
n_estimators = 5000,
max_samples = 100,
bootstrap = True)
bagging_clf2.fit(X_train, y_train)
bagging_clf2.score(X_test, y_test)
# 0.912
理论上集成子模型的数量越多,最终集成模型的准确度就会越高。在具体的学习过程中,采集的样本数据往往会存在噪声或者存在错误的样本,因此通常情况下最终的准确率不会像 99.99% 这样夸张。无论如何,集成学习的 Bagging 策略通常会得到很好的结果。
References: Python3入门机器学习 经典算法与应用: https://coding.imooc.com/class/chapter/169.html#Anchor