一、原理的描述
Adaboost是一种迭代算法,其核心思想是针对同一个训练集训练不同的分类器(弱分类器),然后把这些弱分类器集合起来,构成一个更强的最终分类器(强分类器)。其算法本身是通过改变数据分布来实现的,它根据每次训练集之中每个样本的分类是否正确,以及上次的总体分类的准确率,来确定每个样本的权值。将修改过权值的新数据集送给下层分类器进行训练,最后将每次训练得到的分类器最后融合起来,作为最后的决策分类器。使用adaboost分类器可以排除一些不必要的训练数据特徵,并将关键放在关键的训练数据上面。
- 三个臭皮匠,赛过诸葛亮
- 参考文章一
- 参考文章二
- 1.用大量的<font color =red>病例 == X == 样本</font>让这些<font color = red>新手 == model</font>依次学习,每个<font color = red>大夫 == model == 算法</font>自己琢磨怎样诊断,学习结束后统计一下每个人在这些病例上的诊断准确率
2.训练时,前面的大夫<font color = red>误诊</font>的病例,后面的大夫要<font color = red>重点学习研究 == 样本权重加大 == w</font>,所谓查缺补漏
3.训练结束之后,给每个大夫打分,如果一个大夫对病例学习的误诊率越低,也就是说在这些学习的病例集上诊断的准确率越高,这名大夫在后面诊断病人时的<font color = green>话语权就越大 == 权重大 == 偏大</font> - 诊断过程
- 一个病人之后,8个大夫一起诊断,然后投票。如果一个大夫之前在学习时的诊断准确率为p,误差率e = 1-p,他在投票时的话语权是:
- [图片上传失败...(image-81730-1586219732552)]
- 赵大夫的结果 == 模型预测值
- Adabooting概述
- AdaBoost算法是一种集成学习(ensemble learning)方法。集成学习是机器学习中的一类方法,它对多个机器学习模型进行组合形成一个<font color = red>精度更高的模型就是强学习器</font>,参与组合的模型称为<font color = red>弱学习器(weak learner)</font>。在预测时使用这些弱学习器模型联合起来进行预测;训练时需要用训练样本集依次训练出这些弱学习器。典型的集成学习算法是随机森林和boosting算法,而AdaBoost算法是boosting算法的一种实现版本。
- ,其中是第t个模型的权重,第t个弱学习器的预测
- 分类是判定规则:
- sgn(F(x))表示F(x) 大于0结果正的,如果F(x)小于0,结果就是负的(算法原理基于二分类)
- 算法梳理:
- 训练弱学习器,计算误差率e,可以计算准确率p ,p + e = 1
- 弱学习器的权重
- 没有进行归一化
- 归一化
- Adaboosting中的A是adaptive的意思,所以AdaBoosting表示自适应增强算法
二、主要解决的问题
(1) 二分类,多类单标签问题、多类多标签问题、大类单标签问题
(2)回归问题
三、整体的流程:
- 先通过对N个训练样本的学习得到第一个弱分类器 ;
- 将 分错的样本和其他的新数据一起构成一个新的N个的训练样本,通过对这个样本的学习得到第二个弱分类器 ;
- 将 和 都分错了的样本加上其他的新样本构成另一个新的N个的训练样本,通过对这个样本的学习得到第三个弱分类器 ;
- 最终经过提升的强分类器 。即某个数据被分为哪一类要通过 , ……的多数表决。
注意:每一次都会更新样本的权重(数据的划分正确,降低该样本的权重,数据划分错误就增大它的权重)---》计算该弱分类器的误差率--》更新公式---》再根据公式更新下一轮的样本的权重。
通过以上的操作----经过T次的循环。就得到了最终想要的强分类器。
具体的公式及详细说明如下:
adaboosting算法.png
adaboosting中的Zt是什么.png
每次迭代都是选择相同的模型,上面的ht(x)表示的是弱学习器,前面的αt表示的是该弱学习器的权重。
强学习器.png
多个弱学习器经过多次的迭代,最终得到的就是强学习器H(x)。
其中:sign代表的是符号函数
其最终返回的是那种分类
数学符号函数.png
四、adaboosting简单的算法案例
```python
from sklearn.ensemble import AdaBoostClassifier
import numpy as np
from sklearn import tree
生成数据
X = np.arange(10).reshape(-1,1)
y = np.array([1,1,1,-1,-1,-1,1,1,1,-1])
y
array([ 1, 1, 1, -1, -1, -1, 1, 1, 1, -1])
声明算法,进行训练
# {'SAMME', 'SAMME.R'}
ada = AdaBoostClassifier(algorithm='SAMME',n_estimators=3)
ada.fit(X,y)
AdaBoostClassifier(algorithm='SAMME', base_estimator=None, learning_rate=1.0,
n_estimators=3, random_state=None)
第一棵树划分
y# 4个1 ----> 比例0.4,6个-1 ----> 比例 0.6 gini = 0.4*(1-0.4) + 0.6*(1-0.6) = 0.48
array([ 1, 1, 1, -1, -1, -1, 1, 1, 1, -1])
_ = tree.plot_tree(ada[0])
ada[0].predict(X)#第一棵树的预测值,怎么预测呢?
array([ 1, 1, 1, -1, -1, -1, -1, -1, -1, -1])
output_7_1.png
第一棵树,手动计算,划分
# 样本的初始权重,还没有开始进行训练,所以,所有样本权重一样?
w1 = np.full(shape = 10,fill_value=0.1)
w1
array([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1])
X # 样本中10个数据,划分,0到1之间(threshold阈值0.5)划分;1到2之间(1.5)划分……
# X <= threshold 类别1 阳性 说明不好
# X > threshold 类别-1 阴性 说明健康
array([[0],
[1],
[2],
[3],
[4],
[5],
[6],
[7],
[8],
[9]])
# numpy中的最基本逻辑运算
# 数据分析的三剑客:numpy、pandas、matplotlib
c = y != y1#算数计算的时候,False = 0,True = 1
print(c)
print(c.astype(np.int8))
# 之前讲分类算法,模型评估,使用准确率
# accuracy = (y == y_).mean()
[False True True False False False True True True False]
[0 1 1 0 0 0 1 1 1 0]
# 如果阈值0.5,构建树,结果:
y1 = np.array([1,-1,-1,-1,-1,-1,-1,-1,-1,-1]) #预测结果
e1 = ((y != y1)*d1).sum()#误差
print('方式一',e1)
e1 = (y != y1).mean()
print('方式二',e1)
# 如果阈值1.5,构建树,结果:
y2 = np.array([1,1,-1,-1,-1,-1,-1,-1,-1,-1])
e2 = ((y != y2)*d1).sum()
print('方式一',e2)
e2 = (y != y2).mean()
print('方式二',e2)
方式一 0.5
方式二 0.5
方式一 0.4
方式二 0.4
# 第一颗树划分时,阈值选择了2.5?
# 决策树的裂分,有一个标准!
# for 循环目的:找到分类条件:2.5或者8.5
thresholds = np.arange(0.5,10)
for i,t in enumerate(thresholds,start = 1):#enumerate,获取索引,默认从0开始,
# y_是弱分类器,预测值
y_ = np.array([1]*i + [-1]*(10-i))
# y_ = np.zeros(shape = 10)
# y_[(X <=t).reshape(-1)] = 1
# y_[(X > t).ravel()] = -1
print(t,((y !=y_)*w1).sum())
0.5 0.5
1.5 0.4
2.5 0.30000000000000004
3.5 0.4
4.5 0.5
5.5 0.6
6.5 0.5
7.5 0.4
8.5 0.30000000000000004
9.5 0.4
根据输出的结果,结论,阈值是2.5或者8.5,误差最小的:0.3
选择2.5或者8.5作为裂分条件,代码中一般选择,前面的索引
# 计算第一个弱学习器的权重,相当于大夫的话语权
e1 = 0.3
a1 = 1/2*np.log((1 -e1)/e1 )
print('计算第一个弱学习器的权重:',a1)
计算第一个弱学习器的权重: 0.42364893019360184
更新样本的权重
# 在w1的基础上,进行更新 w1 = [0.1,0.1,0.1……]
y_ = np.array([1]*3 + [-1]*(10-3))
w2 = w1*np.exp(-y*y_*a1)
w2 = w2/w2.sum()
print(w2)
[0.07142857 0.07142857 0.07142857 0.07142857 0.07142857 0.07142857
0.16666667 0.16666667 0.16666667 0.07142857]
第二棵树划分
_ = tree.plot_tree(ada[1])#样本权重,发生变化了
output_19_0.png
手动计算,第二棵树的划分
第二棵树,根据第一棵树的返回结果,进行,学习
第一棵树,更新了样本的权重!w2
thresholds = np.arange(0.5,10)
for i,t in enumerate(thresholds,start = 1):#enumerate,获取索引,默认从0开始,
# y_是弱分类器,预测值
y_ = np.array([1]*i + [-1]*(10-i))
# y_ = np.zeros(shape = 10)
# y_[(X <=t).reshape(-1)] = 1
# y_[(X > t).ravel()] = -1
print(t,((y !=y_)*w2).sum())
0.5 0.6428571428571428
1.5 0.5714285714285714
2.5 0.5
3.5 0.5714285714285714
4.5 0.6428571428571428
5.5 0.7142857142857142
6.5 0.5476190476190476
7.5 0.38095238095238093
8.5 0.21428571428571425
9.5 0.28571428571428564
# 阈值,如果是8.5,那么左边9个数,右边是1个数,计算误差率
y_ = np.array([1]*9 + [-1]*(10-9))#预测值
display(y,y_)
e2 = ((y != y_)*w2).sum()
print('第二棵树的误差率:',e2)
print('样本的权重是:',w2.round(4))
#计算第二棵树的权重
a2 =np.round( 1/2*np.log((1 - e2)/e2),4)
print('第二棵树,权重是:',a2)
array([ 1, 1, 1, -1, -1, -1, 1, 1, 1, -1])
array([ 1, 1, 1, 1, 1, 1, 1, 1, 1, -1])
第二棵树的误差率: 0.21428571428571425
样本的权重是: [0.0714 0.0714 0.0714 0.0714 0.0714 0.0714 0.1667 0.1667 0.1667 0.0714]
第二棵树,权重是: 0.6496
更新第二棵树的样本的权值分布,根据第一棵树的结果w2进行更新
y_ = np.array([1]*9 + [-1]*(10-9))#预测值
w3 = w2*np.exp(-y*y_*a2)
w3 = w3/w3.sum()
print('第二棵树,更新样本权重,更新样本分布:',w3)
第二棵树,更新样本权重,更新样本分布: [0.04545643 0.04545643 0.04545643 0.16665975 0.16665975 0.16665975
0.10606501 0.10606501 0.10606501 0.04545643]
第三棵树划分
_ = tree.plot_tree(ada[2])
output_26_0.png
thresholds = np.arange(0.5,10)
for i,t in enumerate(thresholds,start = 1):#enumerate,获取索引,默认从0开始,
# y_是弱分类器,预测值
y_ = np.array([1]*i + [-1]*(10-i))
# y_ = np.zeros(shape = 10)
# y_[(X <=t).reshape(-1)] = 1
# y_[(X > t).ravel()] = -1
print(t,((y !=y_)*w3).sum())#误差率 + 准确率 = 1
0.5 0.40910788311754365
1.5 0.36365145166003876
2.5 0.318195020202534
3.5 0.4848547715250161
4.5 0.6515145228474983
5.5 0.8181742741699806
6.5 0.7121092674358026
7.5 0.6060442607016245
8.5 0.4999792539674466
9.5 0.5454356854249515
e3 = 0.1820
# 计算第三棵树的权重
y_ = np.array([-1]*6 + [1]*(10-6))
a3 = 1/2*np.log((1 - e3)/e3)
print('第三棵树的权重是:',a3)
# 更新第三棵树的,样本权值分布,权重
w4 = w3*np.exp(-y*y_*a3)
w4 = w4/w4.sum()
print('第三棵树,更新样本权重:',w4.round(3))
第三棵树的权重是: 0.7514278247629759
第三棵树,更新样本权重: [0.125 0.125 0.125 0.102 0.102 0.102 0.065 0.065 0.065 0.125]
集成算法
print(a1,a2,a3)
0.42364893019360184 0.6496 0.7514278247629759
# 第一棵树ft(x)
y1 = np.array([1]*3 + [-1]*(10-3))
# 第二棵树的预测值
y2 = np.array([1]*9 + [-1]*(10-9))#预测值
# 第三棵树,预测值
y3 = np.array([-1]*6 + [1]*(10-6))
F = a1*y1 + a2*y2 + a3*y3
# 将多个弱分类器,整合,变成了强分类器F(X)
F
array([ 0.32182111, 0.32182111, 0.32182111, -0.52547675, -0.52547675,
-0.52547675, 0.97737889, 0.97737889, 0.97737889, -0.32182111])
# 上面的result使我们手动计算的。
result = [-1 if i <0 else 1 for i in F]
result
[1, 1, 1, -1, -1, -1, 1, 1, 1, -1]
# 这个模型预测的返回值
ada.predict(X)
array([ 1, 1, 1, -1, -1, -1, 1, 1, 1, -1])
# 类别 0,1,2目标值有3个类别
y = np.array([1,1,2,0])
# 二进制编码,3个数的二进制,刚好可以表示,3个类别,one-hot:独热编码
y_ = np.array([[0,1,0],
[0,1,0],
[0,0,1],
[1,0,0]])
********
**以上部分内容参考自博客**[https://blog.csdn.net/ben_ben_niao/article/details/47277035](https://blog.csdn.net/ben_ben_niao/article/details/47277035)
网友评论