本文源自微信公众号【Python编程和深度学习】原文链接:[机器学习系列(六)Adaboost](https://mp.weixin.qq.com/s?__biz=MzUxNTY1MjMxNQ==&mid=2247484534&idx=1&sn=6c2a2bfd20b20fe21b5982c241e45d70&chksm=f9b22bc2cec5a2d4626d3b6acfa616347be9863b8fcbadf53761b58bd7eee96168e5ebda325b&token=1098865241&lang=zh_CN#rd),欢迎扫码关注鸭! ![扫它!扫它!扫它](http://cookdata.cn/media/bbs/images/公众号_1602413881117_5d14.jpg =200x200) 前面我们已经介绍了几种不同的分类器,每种分类器都各有优缺点,我们可以借助集成学习的方法将不同的分类器组合起来,将多个弱可学习分类器集成组合成一个强可学习分类器。 集成方法有几种形式: 1) **不同算法**的集成 2) 相同算法的**不同设置**的集成 3) **不同分类器**处理**不同数据集部分**的集成 集成方法主要包括Bagging和Boosting两种方法。 # 目录 [一、Bagging方法:](#1)<br> [二、Boosting方法:](#2)<br> [三、Bagging和Boosting的区别](#3)<br> [四、AdaBoost基本原理介绍](#4)<br> [五、AdaBoost优点和缺点](#5)<br> [六、Python代码](#6)<br> <div id="1"></div> ##一、Bagging方法: 自举汇聚法(bootstap aggregating),通过对训练数据进行**有放回的采样**(自举采样bootstap sampling),弱学习器之间没有依赖关系。 算法步骤: 1) 在训练数据集中采用自举采样方法提取n个训练样本,经过k次提取之后得到k个训练集,每个训练集中有n个样本,由于是有放回的采样,所以有的样本会被多次取到,有的样本可能从来没有被取到; 2) K个训练集经过弱学习器得到k个学习模型; 3) 对k个模型的预测结果采用投票的方式得到最终的分类结果,如果是回归模型,可以取平均值或加权平均值。 Bagging方法最流行的是**随机森林**(random forest),是由Bagging方法和决策树结合。 <div id="2"></div> ##二、Boosting方法: Boosting方法的思想是采用**重赋权**(re-weighting)法迭代地训练弱学习器。 算法步骤: 1) 首先给每个样本赋予一个初始权重值1/m,m为样本数量; 2) 开始训练第一个弱学习器,根据该弱学习器的错误率更新权重,给错误率高的训练样本的权重值变高,在下一次学习中得到更多重视; 3) 依次训练之后多每个弱学习器,并不断迭代更新权重; 4) 对最终的k个弱学习器结果进行整合。 Boosting方法最流行的是**Adaboost**。 <div id="3"></div> ##三、Bagging和Boosting的区别 1)样本选择: Bagging:每次训练的数据集是有放回选取的,它们之间是相互独立的。 Boosting:每次训练的的数据集不变,但每个样例在学习器中的权重发生变化。而权值是根据上一轮的学习结果进行更新。 2)样本权重: Bagging:使用均匀取样,每个样本的权重相同。 Boosting:每个样本的权重不同,根据错误率不断调整样本的权值,错误率越高则权重越大。 3)预测结果权重: Bagging:所有预测结果的权重相等。 Boosting:每个弱学习器都有不同的权重,对于分类误差小的分类器会有更大的权重。 4)计算方式: Bagging:各个学习器可以并行生成,互不影响。 Boosting:各个学习器只能顺序生成,因为后一个模型参数需要基于前一轮模型的结果进行调整。 <div id="4"></div> ##四、AdaBoost基本原理介绍 AdaBoost(Adaptive boosting)是基于Boosting思想的迭代算法,输入样本为 $$ \chi=\left\{\left(x_{1}, y_{1}\right),\left(x_{2}, y_{2}\right), \ldots,\left(x_{n}, y_{n}\right)\right\} $$ 详细的算法描述如下: 1.初始化所有训练数据的权重分布: $$ D_{1}=\left(w_{11}, \ldots, w_{1 i}, \ldots, w_{1 N}\right), \quad w_{1 i}=1 / N, \quad i=1,2, \ldots, N $$ 2.迭代训练弱学习器,并不断更新权重,第m个弱学习器的样本权重为$ {D}_m$,输出值为{-1,1},计算弱分类器在训练集上的分类错误率,值越小其在最终分类器的作用越大。 * 2.1$$ e_{m}=P\left(G_{m}\left(x_{i}\right) \neq y_{i}\right)=\sum_{i=1}^{N} w_{m i}I\left(G_{m}\left(x_{i}\right) \neq y_{i}\right) $$ $I\left(G_{m}\left(x_{i}\right) \neq y_{i}\right) $的取值为0时表示分类正确,取值为1表示分类错误。 * 2.2计算弱学习器的权重系数,当错误率降低的时候权重系数会增大,错误率越小,对最终的预测影响就越大。 $$ \alpha_{m}=\frac{1}{2} \ln \frac{1-e_{m}}{e_{m}} $$ * 2.3更新训练数据集的样本权重 $$ \begin{array}{c} D_{m+1}=\left(w_{m+1,1}, w_{m+1,2} \cdots w_{m+1, i} \cdots, w_{m+1, N}\right), \\ w_{m+1, i}=\frac{w_{m i}}{Z_{m}} \exp \left(-\alpha_{m} y_{i} G_{m}\left(x_{i}\right)\right), i=1,2, \cdots, N \\ Z_{m}=\sum_{i=1}^{N} w_{m i} \exp \left(-\alpha_{m} y_{i} G_{m}\left(x_{i}\right)\right) \end{array} $$ 式中,${Z}_m$是规范化因子,将${w}_{m i}$的值规范化到0-1之间,使得$\sum_{i=1}^{N} w_{m i}=1$ 。对于二分类算法,弱分类器${G}_m(x)$的输出值为{-1,1},类别标签${y}_i$的取值为{-1,1},如果样本被正确分类,$y_{i} G_{m}(x)>0,\quad w_{m+1, i}$取值较小,相反如果样本分类错误,$y_{i} G_{m}(x)<0, \quad w_{m+1, i}$取值较大,则权重变高,在之后的训练过程中会得到更多的重视。 3.多个弱学习器的结合 Adaboost对于弱学习器的结合策略是加权平均, $$ f(x)=\sum_{m=1}^{M} \alpha_{m} G_{m}(x) $$ 那么最终的分类器为: $$ G(x)=\operatorname{sign}(f(x))=\operatorname{sign}\left(\sum_{m=1}^{M} \alpha_{m} G_{m}(x)\right) $$ <div id="5"></div> ##五、AdaBoost优点和缺点 **优点** (1)算法集成了众多机器学习算法构建的弱分类器,不容易发生过拟合; (2)相对于bagging算法和Random Forest算法,AdaBoost充分考虑的每个分类器的权重,可以取得较高的准确性; (3)AdaBoost的训练参数很少,不需要调节太多的参数。 **缺点** (1)由于AdaBoost是集成学习方法,其迭代次数基于弱分类器数目,因此迭代次数难以设定,可以使用交叉验证来进行确定; (2)由于需要迭代所有分类器,因此训练比较耗时; (3)对异常样本噪声敏感,异常样本在迭代中可能会获得较高的权重,影响最终的强学习器的预测准确性,同时数据正负样本不均衡也会导致实际准确性下降。 Adaboost分类器结构: ![](http://cookdata.cn/media/bbs/images/640_1616469602351_5d14.jpg) <div id="6"></div> ##六、Python代码 一个简单实例,来自飘涯 ```python #-*- conding:utf-8 -*- import numpy as np import matplotlib.pyplot as plt import matplotlib as mpl from sklearn.ensemble import AdaBoostClassifier#adaboost引入方法 from sklearn.tree import DecisionTreeClassifier from sklearn.datasets import make_gaussian_quantiles#造数据 ## 设置属性防止中文乱码 mpl.rcParams['font.sans-serif'] = [u'SimHei'] mpl.rcParams['axes.unicode_minus'] = False ## 创建数据 X1, y1 = make_gaussian_quantiles(cov=2., n_samples=200, n_features=2, n_classes=2, random_state=1)#创建符合高斯分布的数据集 X2, y2 = make_gaussian_quantiles(mean=(3, 3), cov=1.5, n_samples=300, n_features=2, n_classes=2, random_state=1) X = np.concatenate((X1, X2)) y = np.concatenate((y1, - y2 + 1)) plot_step = 0.02 x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1 xx, yy = np.meshgrid(np.arange(x_min, x_max, plot_step), np.arange(y_min, y_max, plot_step)) #构建adaboost模型 bdt = AdaBoostClassifier(DecisionTreeClassifier(max_depth=1), algorithm="SAMME.R",#可以不写 n_estimators=200) #数据量大的时候,可以增加内部分类器的树深度,也可以不限制树深 #max_depth树深,数据量大的时候,一般范围在10——100之间 #数据量小的时候,一般可以设置树深度较小,或者n_estimators较小 #n_estimators 迭代次数或者最大弱分类器数:200次 #base_estimator:DecisionTreeClassifier 选择弱分类器,默认为CART树 #algorithm:SAMME 和SAMME.R 。运算规则,后者是优化算法,以概率调整权重,迭代速度快, #需要能计算概率的分类器支持 #learning_rate:0<v<=1,默认为1,正则项 衰减指数 #loss:linear、‘square’exponential’。误差计算公式:一般用linear足够 bdt.fit(X, y) #预测 Z = bdt.predict(np.c_[xx.ravel(), yy.ravel()]) #设置维度 Z = Z.reshape(xx.shape) ## 画图 plot_colors = "br" class_names = "AB" plt.figure(figsize=(10, 5), facecolor='w') #局部子图 plt.subplot(121) plt.pcolormesh(xx, yy, Z, cmap=plt.cm.Paired) for i, n, c in zip(range(2), class_names, plot_colors): idx = np.where(y == i) plt.scatter(X[idx, 0], X[idx, 1], c=c, cmap=plt.cm.Paired, label=u"类别%s" % n) plt.xlim(x_min, x_max) plt.ylim(y_min, y_max) plt.legend(loc='upper right') plt.xlabel('x') plt.ylabel('y') plt.title(u'AdaBoost分类结果,正确率为:%.2f%%' % (bdt.score(X, y) * 100)) #获取决策函数的数值 twoclass_output = bdt.decision_function(X) #获取范围 plot_range = (twoclass_output.min(), twoclass_output.max()) plt.subplot(122) for i, n, c in zip(range(2), class_names, plot_colors): #直方图 plt.hist(twoclass_output[y == i], bins=20, range=plot_range, facecolor=c, label=u'类别 %s' % n, alpha=.5) x1, x2, y1, y2 = plt.axis() plt.axis((x1, x2, y1, y2 * 1.2)) plt.legend(loc='upper right') plt.ylabel(u'样本数') plt.xlabel(u'决策函数值') plt.title(u'AdaBoost的决策值') plt.tight_layout() plt.subplots_adjust(wspace=0.35) plt.show() ``` 结果如下: ![](http://cookdata.cn/media/bbs/images/6401.webp_1616469741828_5d14.jpg) 参考: 李航,《统计学习方法》 第八章 https://blog.csdn.net/qq_24519677/java/article/details/81910112 https://www.jianshu.com/p/b86a0863fe45