自适应增强 | Adaptive Boosting (Adaboost)
type
Post
status
Published
summary
AdaBoost是Boosting算法中比较有代表性的一个,主要原理是通过不断调整样本和弱学习器的权重来输出最终结果。
slug
adaboost
date
Jun 22, 2020
tags
boosting
Adaboost
category
机器学习
password
icon
URL
Property
Feb 28, 2024 01:09 PM
AdaBoost概述
Adaboost既可以用作分类,也可以用作回归。
在boosting中我们介绍过, Boosting算法的工作机制是首先从训练集用初始权重训练出一个弱学习器1,根据弱学习的学习误差率表现来更新训练样本的权重,使得之前弱学习器1学习误差率高的训练样本点的权重变高,使得这些误差率高的点在后面的弱学习器2中得到更多的重视。然后基于调整权重后的训练集来训练弱学习器2.,如此重复进行,直到弱学习器数达到事先指定的数目T,最终将这T个弱学习器通过集合策略进行整合,得到最终的强学习器。
只要是boosting大家族的算法,都要解决下面4个问题。
- 如何计算学习误差率e?
- 如何得到弱学习器权重系数α?
- 如何更新样本权重D?
- 使用何种结合策略?
AdaBoost原理
输入为样本集 输出为 − 1, + 1 ,弱分类器算法, 弱分类器迭代次数K。
输出为最终的强分类器
1、初始化样本集权重为
2、对于:
a) 使用具有权重 Dk 的样本集来训练数据,得到弱分类器
b) 计算的分类误差率
c) 计算弱分类器的系数
d) 更新样本集的权重分布
这里ZkZk是规范化因子
3、构建最终分类器为:
对于Adaboost多元分类算法,其实原理和二元分类类似,最主要区别在弱分类器的系数上。比如Adaboost SAMME算法,它的弱分类器的系数
其中R为类别数。从上式可以看出,如果是二元分类,R=2,则上式和我们的二元分类算法中的弱分类器的系数一致。
Adaboost 总结
- 初始化训练样本的权值分布,每个样本具有相同权重;
- 训练弱分类器,如果样本分类正确,则在构造下一个训练集中,它的权值就会被降低;反之提高。用更新过的样本集去训练下一个分类器;
- 将所有弱分类组合成强分类器,各个弱分类器的训练过程结束后,加大分类误差率小的弱分类器的权重,降低分类误差率大的弱分类器的权重。
Adaboost优缺点
优点
- 分类精度高;
- 可以用各种回归分类模型来构建弱学习器,非常灵活;
- 不容易发生过拟合。
缺点
- 对异常点敏感,异常点会获得较高权重。
代码实现(二分类)
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]) # 第一棵树!!!!!! # 样本的初始权重,还没有开始进行训练,所以,所有样本权重一样? w1 = np.full(shape = 10,fill_value=0.1) # 样本中10个数据,划分,0到1之间(threshold阈值0.5)划分;1到2之间(1.5)划分…… thresholds = np.arange(0.5,10) # 生成0.5到9.5中间间隔1的10个数 for i,t in enumerate(thresholds,start = 1): #enumerate,获取索引,默认从0开始, y_ = np.array([1]*i + [-1]*(10-i)) # 计算预测值 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] ''' # 第二棵树!!!!!!!!!! thresholds = np.arange(0.5,10) for i,t in enumerate(thresholds,start = 1): #enumerate,获取索引,默认从0开始, y_ = np.array([1]*i + [-1]*(10-i)) # 计算预测值 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) ''' 第二棵树的误差率: 0.21428571428571425 ''' a2 =np.round( 1/2*np.log((1 - e2)/e2),4) print('第二棵树,权重是:',a2) # 计算第二棵树的权重 ''' 第二棵树,权重是: 0.6496 ''' # 更新样本权重 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] ''' # 第三棵树!!!!!!!!!! thresholds = np.arange(0.5,10) for i,t in enumerate(thresholds,start = 1):#enumerate,获取索引,默认从0开始, y_ = np.array([1]*i + [-1]*(10-i)) 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) ''' 第三棵树的权重是: 0.7514278247629759 ''' # 更新第三棵树的,样本权值分布,权重 w4 = w3*np.exp(-y*y_*a3) w4 = w4/w4.sum() print('第三棵树,更新样本权重:',w4.round(3)) ''' 第三棵树,更新样本权重: [0.125 0.125 0.125 0.102 0.102 0.102 0.065 0.065 0.065 0.125] ''' # 集成算法 # 第一棵树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 = [-1 if i <0 else 1 for i in F] result ''' [1, 1, 1, -1, -1, -1, 1, 1, 1, -1] ''' # 分类成功!