Adaboost算法

Adaboost的学习内容整理自菊安酱小姐姐的直播视频,原视频链接:【菊安酱的机器学习】第6期 Adaboost算法,小姐姐还有完整的一系列机器学习视频课程,感兴趣的可以去看看。
Adaboost也属于集成学习,随机森林那里已经提到集成学习,但只写了Bagging算法和Boosting算法,这里补充上集成学习的理解以及弱分类器的结合策略。
一、集成学习(Ensemble learning):将若干个弱分类器通过一定的策略组合之后产生一个强分类器。弱分类器(基分类器)指的是那些分类准确率只比随机猜测略好一点的分类器,而强分类器的分类准确率高很多。
三种结合策略:
1、平均法:对于数值类的回归预测问题,通常使用的结合策略是平均法,对于若干个弱学习器的输出进行平均得到最终的预测输出。假设最终得到的n个弱分类器为{ h 1 , h 2 , . . . , h n h_{1},h_{2},...,h_{n} h1,h2,...,hn},最简单的平均是算术平均,最终预测是 H ( x ) = 1 n ∑ 1 n h i ( x ) H\left ( x \right )=\frac{1}{n}\sum_{1}^{n}h_{i}\left ( x \right ) H(x)=n11nhi(x)
如果每个弱分类器有一个权重w,则最终预测是 H ( x ) = 1 n ∑ 1 n w i h i ( x ) ( w i ≥ 0 , ∑ 1 n w i = 1 ) H\left ( x \right )=\frac{1}{n}\sum_{1}^{n}w_{i}h_{i}\left ( x \right )\left ( w_{i} \geq 0,\sum_{1}^{n}w_{i}=1\right ) H(x)=n11nwihi(x)(wi0,1nwi=1)
2、投票法:对于分类问题的预测,通常使用的是投票法。假设预测类别是{ c 1 , c 2 , . . . , c K c_{1},c_{2},...,c_{K} c1,c2,...,cK},对于任意一个预测样本x,n个弱学习器的预测结果分别是{ h 1 ( x ) , h 2 ( x ) , . . . , h n ( x ) h_{1}\left ( x \right ),h_{2}\left ( x \right ),...,h_{n}\left ( x \right ) h1(x),h2(x),...,hn(x)}。最简单的投票法是相对多数投票法(少数服从多数),n个弱学习器对样本x的预测结果中,数量最多的类别 c i c_{i} ci为最终的分类类别。如果不止一个类别获得最高票,则随机选择一个做最终类别。
稍微复杂的投票法是绝对多数投票法,在相对多数投票法的基础上,不光要求获得最高票,还要求票过半数,否则会拒绝预测。
更加复杂的是加权投票法,和加权平均法一样,每个弱学习器的分类票数要乘以一个权重,最终将各个类别的加权票数求和,最大的值对应的类别为最终类别。
3、学习法:代表方法是stacking,不是对弱学习器的结果做简单的逻辑处理,而是再加上一层学习器,弱学习器的结果作为该学习器的输入,得到最终结果。此时弱学习器称为初级学习器,用于结合的学习器称为次级学习器。
二、Adaboost是adaptive boosting(自适应boosting)的缩写,算法步骤如下:
1、计算样本权重
赋予训练集中每个样本一个权重,构成权重向量D,将权重向量D初始化相等值。假设有n个样本的训练集{( x 1 , y 1 x_{1},y_{1} x1,y1),( x 2 , y 2 x_{2},y_{2} x2,y2),…,( x n , y n x_{n},y_{n} xn,yn)},设定每个样本的权重都相等,则权重为 1 n \frac{1}{n} n1
2、计算错误率
在训练集上训练出一个弱分类器,并计算分类器的错误率: ϵ = 分 错 的 数 量 样 本 总 数 \epsilon =\frac{分错的数量}{样本总数} ϵ=
3、计算弱分类器权重
为当前分类器赋予权重值 α \alpha α,计算公式为: α = 1 2 l n ( 1 − ϵ ϵ ) \alpha=\frac{1}{2}ln\left ( \frac{1-\epsilon }{\epsilon } \right ) α=21ln(ϵ1ϵ)
4、调整权重值
根据上一次训练结果,调整权重值(上一次分对的权重降低,分错的权重增加)。如果第i个样本被正确分类,则该样本权重更改为: D i ( t + 1 ) = D i ( t ) e − α S u m ( D ) D_{i}^{\left ( t+1 \right )}=\frac{D_{i}^{\left ( t \right )}e^{-\alpha }}{Sum\left ( D \right )} Di(t+1)=Sum(D)Di(t)eα
如果第i个样本被分错,则该样本权重更改为: D i ( t + 1 ) = D i ( t ) e α S u m ( D ) D_{i}^{\left ( t+1 \right )}=\frac{D_{i}^{\left ( t \right )}e^{\alpha }}{Sum\left ( D \right )} Di(t+1)=Sum(D)Di(t)eα
之后,在同一数据集上再一次训练弱分类器,然后循环上述过程,直到训练错误率为0,或者弱分类器的数目达到指定值。
AdaBoost算法特点:
优点: 泛化错误率低,易编码,可以应用在大部分分类器上。
缺点: 对离群点敏感。
三、以马疝病数据集练习实践,实现Adaboost算法并将其应用于给定一系列马的特征的情况下,判断马是否患病。原始数据分为训练集和测试集,其中一个样本如下,有21个特征,类别标签为1和-1。
在这里插入图片描述
导入外部数据源的相关代码如下:

import numpy as np

#加载外部数据源
def load_data_set(filename):
    num_features = len(open(filename).readline().split('\t'))   #获得字段数量
    data_mat = []
    label_mat = []
    fr = open(filename)
    for line in fr.readlines(): #逐行读取文件
        line_arr = []
        cur_line = line.strip().split('\t') #分离各个字段
        for i in range(num_features - 1):
            line_arr.append(float(cur_line[i])) #存储每一行的特征
        data_mat.append(line_arr)   #存储所有样本特征
        label_mat.append(float(cur_line[-1]))   #存储样本类别
    return data_mat, label_mat

构建单层决策树弱分类器的代码如下:

#根据thresh_ineq标志进行分类,标志为lt,将小于阈值的设为-1,标志为gt,将大于阈值的设为-1
def stump_classify(data_matrix, dimen, thresh_val, thresh_ineq):    #dimen表示第dimen列,即第几个特征,分类依据特征;thresh_val是阈值
    ret_array = np.ones((np.shape(data_matrix)[0], 1))  #初始化结果集为1
    if thresh_ineq == 'lt':
        ret_array[data_matrix[:, dimen] <= thresh_val] = -1.0   #小于阈值,赋值为-1
    else:
        ret_array[data_matrix[:, dimen] > thresh_val] = -1.0    #大于阈值,赋值为-1
    return ret_array

#找到最佳单层决策树
def build_stump(data_arr, class_labels, d):
    data_matrix = np.mat(data_arr)  #转化为矩阵形式,便于计算
    label_mat = np.mat(class_labels).T  #转置类别集
    m, n = np.shape(data_matrix)    #获得特征集行、列数量
    num_steps = 10.0    #值用来划分步长
    best_stump = {} #用来存储最佳分类器
    best_clas_est = np.mat(np.zeros((m, 1)))    #存储分类结果
    min_error = np.inf  #最小误差初始化为无穷大
    for i in range(n):  #遍历所有特征
        range_min = data_matrix[:, i].min() #获取特征中的最小值
        range_max = data_matrix[:, i].max() #获取特征中的最大值
        step_size = (range_max - range_min) / num_steps #设定步长
        for j in range(-1, int(num_steps) + 1): #循环增加步长数量改变阈值
            for inequal in ['lt', 'gt']:    #大于阈值归为1,还是小于阈值归为1的循环
                thresh_val = range_min + float(j) * step_size   #计算阈值
                predicted_vals = stump_classify(data_matrix, i, thresh_val,inequal) #计算分类结果
                err_arr = np.mat(np.ones((m, 1)))   #初始化误差矩阵全为一
                err_arr[predicted_vals == label_mat] = 0    #分类正确的,赋值为0
                weighted_error = d.T * err_arr  #计算分类误差
                if weighted_error < min_error:  #找到误差最小的分类方式
                    min_error = weighted_error
                    best_clas_est = predicted_vals.copy()
                    best_stump['dim'] = i   #分类特征
                    best_stump['thresh'] = thresh_val   #分类阈值
                    best_stump['ineq'] = inequal    #分类方式
    return best_stump, min_error, best_clas_est #输出最好的分类方式、最小误差、分类结果

Adaboost实现代码如下:

#Adaboost训练过程
def adaboost_trainDS(data_arr, class_labels, num_iter):  #num_iter迭代次数
    weak_class_arr = [] #存储每次迭代最佳分类器
    m = np.shape(data_arr)[0]   #获得样本数量
    d = np.mat(np.ones((m, 1)) / m) #初始化权重都相等
    agg_class_est = np.mat(np.zeros((m, 1)))
    for i in range(num_iter):
        best_stump, error, class_est = build_stump(data_arr, class_labels, d)   #找到具有最小错误率的单层决策树
        alpha = float(0.5 * np.log((1.0 - error) / max(error, 1e-16)))  #计算弱分类器权重alpha,1e-16是避免除零溢出,分母不能为0
        best_stump['alpha'] = alpha #记录权重
        weak_class_arr.append(best_stump)   #记录分类器
        expon = np.multiply(-1 * alpha * np.mat(class_labels).T, class_est) #计算e的指数项,分类正确的为-α,分类错误的为α
        d = np.multiply(d, np.exp(expon))
        d = d / d.sum() #更新样本权重
        agg_class_est += alpha * class_est  #记录每个数据点的类别估计累计值
        agg_errors = np.multiply(np.sign(agg_class_est) != np.mat(class_labels).T, np.ones((m, 1))) #计算误差
        error_rate = agg_errors.sum() / m   #错误率
        if error_rate == 0.0:   #错误率为0时退出循环
            break
    return weak_class_arr, agg_class_est    #输出每次迭代最佳分类器,最终每个数据点的类别估计累计值

#基于Adaboost的分类
def ada_classify(dat2class, classifier_arr):    #classifier_arr弱分类器集合
    data_matrix = np.mat(dat2class)
    m = np.shape(data_matrix)[0]    #获得样本数量
    agg_class_est = np.mat(np.zeros((m, 1)))
    for i in range(len(classifier_arr)):    #遍历所有弱分类器
        class_est = stump_classify(data_matrix, classifier_arr[i]['dim'],classifier_arr[i]['thresh'],
                                   classifier_arr[i]['ineq'])   #获得每个分类器的结果
        agg_class_est += classifier_arr[i]['alpha'] * class_est #每个数据点的类别估计累计值
    return np.sign(agg_class_est)   #输出类别

对数据进行训练并预测的代码如下:

def test_horse():
    data_arr,label_arr=load_data_set('horseColicTraining.txt')	#加载训练数据
    classifier_arr,agg_class_est=adaboost_trainDS(data_arr,label_arr,500)	#训练模型
    train_prediction=np.sign(agg_class_est)	#获得预测结果
    train_err_arr=np.mat(np.ones((len(data_arr),1)))
    train_err_num=train_err_arr[train_prediction!=np.mat(label_arr).T].sum()	#预测错误的数量
    print("train accuracy:%.2f"%(1-train_err_num/float(len(data_arr))))	#训练集预测准确率

    test_arr,test_label_arr=load_data_set('horseColicTest.txt')	#加载测试数据
    test_prediction=ada_classify(test_arr,classifier_arr)	#获得预测结果
    test_err_arr=np.mat(np.ones((len(test_arr),1)))
    test_err_num=test_err_arr[test_prediction!=np.mat(test_label_arr).T].sum()	#预测错误的数量
    print("test accuracy:%.2f"%(1-test_err_num/float(len(test_arr))))	#测试集预测准确率
test_horse()

使用不同数量的弱分类器进行训练,即改变Adaboost训练过程num_iter参数的值,测试结果如下:

弱分类器数量训练集准确率测试集准确率
10.720.73
100.770.76
500.810.79
1000.810.78
5000.840.75

可以看到,当弱分类器数量为50时,预测结果最好。随着弱分类器数量的增加,训练集准确率虽然提高了,但是测试集准确率在下降,模型存在过拟合问题。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值