例如,你可以训练一组决策树分类器,每一棵树都基于训练集不同的随机子集进行训练。做出预测时,你只需要获得所有树各自的预测,然后给出得票最多的类别作为预测结果。这样一组决策树的集成被称为随机森林,尽管很简单,但它是迄今可用的最强大的机器学习算法之一。
集成学习
它的工作原理是生成多个分类器/模型, 各自独立地 学习和作出预测。这些预测最后结合成组合预测,因此优于任何一个单分类的做出预测。
集成学习, ensemble learning (EL) ,它将多个学习器集成在一起,有时也会被称为多分类器系统(multi-classifier system)、委员会学习(committee learning)、Modular systems、classifier fusion、combination、aggregation等。这些概念相互之间互相联系,又有些许区别,对于概念的定义业界还没有达成共识。整个算法所表现出来的性能非常地强悍,许多高水平的竞赛(Knowledge Discovery and Data Mining、Kaggle)中都是首选。
- 硬投票法:聚合每个分类器的预测,然后将得票最多的结果作为预测类别。
- 软投票法:如果所有分类器都能够估算出类别的概率(即有
predict_proba()
方法),那么你可以将概率在所有单个分类器上平均,然后让Scikit-Learn给出平均概率最高的类别作为预测。
获得不同种类分类器的方法:
- 使用不同的训练算法。
- 算法相同,但是在不同的训练集随机子集上进行训练。
采样时如果将样本放回: bagging 。bootstrap aggregating的缩写,也叫自举汇聚法 采样时样本不放回: pasting
总之,bagging生成的模型通常更好,这也就是为什么它更受欢迎。
Boosting:这一类个体之间学习器之间存在强依赖关系,必须使用串行的方法去学习。
Bagging:这一类方法个体学习器之间不存在强依赖关系,因此可用并行的方式去学习。
1990年Robert E Schapire提出Boosting 方法。大体思想是对容易分类错误的训练实例加强学习,与人类重复背英语单词类似。
具体的实现方法是:首先给每一个训练样例赋予相同的权重,然后训练第一个基本分类器并用它来对训练集进行测试,对于那些分类错误的测试样例提高其权重(实际算法中是降低分类正确的样例的权重),然后用调整后的带权训练集训练第二个基本分类器,然后重复这个过程直到最后得到一个足够好的学习器。
Boosting由于各基学习器之间存在强依赖关系,因此只能串行处理,也就是Boosting实际上是个迭代学习的过程。
Boosting算法的典型代表有AdaBoost和XGBoost。
加法模型:强分类器由一系列弱分类器线性相加而成。
bagging
自举汇聚法(bootstrap aggregating),也称为bagging方法。1996年伯克利大学Leo Breiman 提出Bagging (Bootstrap AGGregatING)方法。其思想是对训练集有放回地抽取训练样例,从而为每一个基本分类器都构造出一个跟训练集同样大小但各不相同的的训练集,从而训练出不同的基本分类器。Bagging算法是并行式集成学习方法著名代表,基于自助采样法(bootstrap sampling)
给定包含 m 个样本的数据集,我们先随机取出一个样本放入采样集中,再把该样本放回初始数据集,使得下次采样时该样本仍有可能被选中,这样,经过 m 次随机采样操作,我们得到含 m 个样本的采样集,新数据集和原数据集的大小相等,初始训练集中有的样本在采样集里多次出现,有的则从未出现,初始训练集中约有63.2%的样本出现在来样集中。
照这样,我们可采样出 T 个含m 个训练样本的采样集,然后基于每个采样集训练出一个基学习器,再将这些基学习器进行结合。
对分类任务使用简单投票法,对回归任务使用简单平均法.若分类预测时出现两个类收到同样票数的情形,则最简单的做法是随机选择一个,也可进一步考察学习器投票的置信度来确定最终胜者。 对于缺失得数据点我们常常称之为袋外数据(Out Of Bag, 简称OOB)。这些数据没有参与训练集模型的拟合,因此可以用来检测模型的泛化能力。
$m$个样本中,一个样本被随机抽取到的概率是$\frac{1}{m}$, 则有:
bagging方法的各个学习器之间不存在依赖性,因此可以并行学习,代表性方法有随机森林等。
boosting
每个新分类器都根据已训练出的分类器的性能来进行训练,各个学习器之间存在依赖关系,必须串行生成。分类的结果是基于所有分类器的加权求和结果的,每个权重代表的是其对应分类器在上一轮迭代中的成功度。
AdaBoost
AdaBoost(Adaptive Boosting,自适应增强),1997年Yoav Freund提出AdaBoost(Adaptive Boosting)方法。
训练数据中的每个样本,并赋予其一个权重,这些权重构成了向量D。一开始,这些权重都初始化成相等值。首先在训练数据上训练出一个弱分类器并计算该分类器的错误率,然后在同一数据集上再次训练弱分类器。在分类器的第二次训练当中,将会重新调整每个样本的权重,其中第一次分对的样本的权重将会降低,而第一次分错的样本的权重将会提高。为了从所有弱分类器中得到最终的分类结果,AdaBoost为每个分类器都分配了一个权重值alpha,这些alpha值是基于每个弱分类器的错误率进行计算的。计算出alpha值之后,可以对权重向量D进行更新,以使得那些正确分类的样本的权重降低而错分样本的权重升高。
其中,错误率$\varepsilon$的定义为:
alpha计算:
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
iris = load_iris()
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=22)
ada_clf = AdaBoostClassifier(DecisionTreeClassifier(max_depth=2), n_estimators=500)
ada_clf.fit(x_train, y_train)
ada_clf.score(x_test, y_test)
Adaboost采用加权投票的方法,分类误差小的弱分类器的权重大,而分类误差大的弱分类器的权重小。
GBDT
梯度提升决策树(Gradient Boosting Decision Tree,GBDT),又叫 MART(Multiple Additive Regression Tree) ,是一种迭代的决策树算法,该算法由多棵决策树组成,GBDT 的核心在于累加所有树的结果作为最终结果,所有GBDT中的树都是CART回归树。不是分类树,它是属于 Boosting 策略。GBDT 是被公认的泛化能力较强的算法。
GBDT 由三个概念组成:Regression Decision Tree(即 DT)、Gradient Boosting(即 GB),和 Shrinkage(缩减)
基于梯度提升算法的学习器叫做 GBM(Gradient Boosting Machine)。理论上,GBM 可以选择各种不同的学习算法作为基学习器。GBDT 实际上是 GBM 的一种情况。
让新的预测器针对前一个预测器的残差进行拟合,每一棵回归树学习的是之前所有树的结论和残差,拟合得到一个当前的残差回归树,残差的意义如公式:残差 = 真实值 - 预测值 。提升树即是整个迭代过程生成的回归树的累加。
梯度提升决策树(Gradient Boosting Decision Tree,GBDT),2001年,Jerome H. Friedman在论文《 Greedy function approximation : A gradient boosting machine》中提出。
XGBoost
XGBoost(eXtreme Gradient Boosting)极致梯度提升,是基于GBDT的一种算法。2016年,陈天奇在论文《 XGBoost:A Scalable Tree Boosting System》中正式提出。 XGBoost 是大规模并行 boosting tree 的工具,它是目前最快最好的开源 boosting tree 工具包,比常见的工具包快 10 倍以上。XGBoost 和GBDT 两者都是 boosting 方法,除了工程实现、解决问题上的一些差异外,最大的不同就是目标函数的定义。 XGBoost = GBDT损失函数 + L2正则化项
LightGBM
LightGBM 由微软提出,主要用于解决 GDBT 在海量数据中遇到的问题,以便其可以更好更快地用于工业实践中,其相对 XGBoost 具有训练速度快、内存占用低的特点。这个要在后面的博客里详细写。
LightGBM = XGBoost + Histogram + GOSS(单边梯度采样) + EFB(互斥特征捆绑)
程序实现
随机森林
class sklearn.ensemble.RandomForestClassifier(n_estimators=100, *, criterion='gini', max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features='auto', max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, bootstrap=True, oob_score=False, n_jobs=None, random_state=None, verbose=0, warm_start=False, class_weight=None, ccp_alpha=0.0, max_samples=None)
参数 criterion 参阅前面的博客
参数 n_estimators int, default=100
森林中树木的数量
参数 bootstrap bool, default=True
控制抽样技术的参数,默认为True。采用有放回的随机抽样数据来形成训练数据。
参数 oob_score bool or callable, default=False
用袋外数据来测试模型。袋外样本误差是测试数据集误差的无偏估计,所以推荐设置True。
参数 n_jobs
参数 max_samples
参数 max_depth
若等于None,表示决策树在构建最优模型的时候不会限制子树的深度。如果模型样本量多,特征也多的情况下,推荐限制最大深度;若样本量少或者特征少,则不限制最大深度。
默认情况下,SVC类是不行的,所以你需要将其超参数probability设置为True(这会导致SVC使用交叉验证来估算类别概率,减慢训练速度,并会添加predict_proba() 方法)
如果基本分类器可以估计类别概率(如果它具有 predict_proba()
方法),则 BaggingClassifier
自动执行软投票而不是硬投票,在决策树分类器中就是这种情况。
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
iris = load_iris()
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=22)
clf = RandomForestClassifier(random_state=0)
clf.fit(x_train, y_train)
y_predict = clf.predict(x_test)
accurcy = accuracy_score(y_test, y_predict)
print(accurcy)
投票分类器
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.ensemble import RandomForestClassifier, VotingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
iris = load_iris()
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=22)
clf2 = RandomForestClassifier()
clf1 = LogisticRegression(multi_class='multinomial')
svm_clf = SVC()
voting_clf = VotingClassifier(estimators=[('lr', clf1), ('rf', clf2), ('svc', svm_clf)], voting='hard')
voting_clf.fit(x_train, y_train)
for clf in (clf1, clf2, 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.9473684210526315
# RandomForestClassifier 0.9473684210526315
# SVC 0.9473684210526315
# VotingClassifier 0.9210526315789473
AdaBoost
多分类
class sklearn.ensemble.AdaBoostClassifier(base_estimator=None, *, n_estimators=50, learning_rate=1.0, algorithm='SAMME.R', random_state=None)
参数 base_estimator object, default=None
需要支持示例权重,以及适当的classes_和n_classes_属性。如果没有,那么基础估计器是DecisionTreeClassifier(max_depth=1)
参数 n_estimators int, default=50
终止推进的估计器的最大数目。如果完全拟合,学习过程就会提前停止。
# 为100个弱学习器拟合AdaBoost分类器:
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_iris
from sklearn.ensemble import AdaBoostClassifier
X, y = load_iris(return_X_y=True)
clf = AdaBoostClassifier(n_estimators=100)
#通过交叉验证评估准确率
scores = cross_val_score(clf, X, y, cv=5)
scores.mean()
GBDT
Gradient Tree Boosting or Gradient Boosted Decision Trees (GBDT) is a generalization of boosting to arbitrary differentiable loss functions, see the seminal work of [Friedman2001]. GBDT is an excellent model for both regression and classification, in particular for tabular data.
这一部分不如直接用LightGBM
>>> from sklearn.ensemble import HistGradientBoostingClassifier
>>> from sklearn.datasets import make_hastie_10_2
>>> X, y = make_hastie_10_2(random_state=0)
>>> X_train, X_test = X[:2000], X[2000:]
>>> y_train, y_test = y[:2000], y[2000:]
>>> clf = HistGradientBoostingClassifier(max_iter=100).fit(X_train, y_train)
>>> clf.score(X_test, y_test)
0.8965
参阅
- 经典机器学习系列之【集成学习】 - 小小何先生的文章 - 知乎
- 随机森林算法参数解释及调优 - 胡卫雄的文章 - 知乎
- 中文文档
- 官方文档
- 集成学习(Ensemble Learning)简单入门
- 【机器学习】Bagging算法 - leedq的文章 - 知乎
- GBDT的原理、公式推导、Python实现、可视化和应用 - 刘启林的文章 - 知乎
- XGBoost的原理、公式推导、Python实现和应用 - 刘启林的文章 - 知乎
- XGBoost、LightGBM的原理、公式推导、Python实现和应用 - 大火山的文章 - 知乎
- 博客园 Python机器学习笔记:XgBoost算法
- Boosting算法总结 - 憧憬的文章 - 知乎
- 简书 GBDT:梯度提升决策树