按照上一篇博客中搭建好环境后,我们正式进入ML算法的学习。首先看第一个adaboost。
本文包含以下几个方面的内容:
- adaboost算法的基础知识
- python3的实现过程
- 实现过程中学习到的python3技巧
adaboost算法的基本知识
adaboost的源头在《A Decision-Theoretic Generalization of On-Line Learning and an Application to Boosting》这篇论文里,是1996年的工作,关于这篇论文的解读笔记,会在接下来的几天里整理好,写成博客。这里引用一下其他人的解读点击打开链接、还有这个,做一个快速的入门。
(1)补充一下大家看点击打开链接的一些先验知识:
分类器:二分类,标签+1;-1
误差计算方法:,y是标签如【-1,-1,+1】,G(x)是分类器计算结果如【+1,-1,+1】,错的越多指数越大,loss越大
样本权重*当前弱分类器的分类误差==强分类器的分类误差
最后算出来的分类器权重,是以loss最小为目标的。
这一步的推导中,下面的那个公式中F的下标应该是m-2
扫描二维码关注公众号,回复: 2370229 查看本文章
(2)粘贴博客中关于adaboost中比较重要的一些概念,详细内容大家还是看博客原文:
- Adaboost算法基本原理就是将多个弱分类器(弱分类器一般选用单层决策树)进行合理的结合,使其成为一个强分类器。
- Adaboost采用迭代的思想,每次迭代只训练一个弱分类器,训练好的弱分类器将参与下一次迭代的使用。也就是说,在第N次迭代中,一共就有N个弱分类器,其中N-1个是以前训练好的,其各种参数都不再改变,本次训练第N个分类器。其中弱分类器的关系是第N个弱分类器更可能分对前N-1个弱分类器没分对的数据,最终分类输出要看这N个分类器的综合效果。
- AdaBoost改变了训练数据的权值,也就是样本的概率分布,其思想是将关注点放在被错误分类的样本上,减小上一轮被正确分类的样本权值,提高那些被错误分类的样本权值。
- Adaboost算法中有两种权重,一种是数据的权重,另一种是弱分类器的权重。其中,数据的权重主要用于弱分类器寻找其分类误差最小的决策点,找到之后用这个最小误差计算出该弱分类器的权重(发言权),分类器权重越大说明该弱分类器在最终决策时拥有更大的发言权
- 迭代过程:
- 第i轮迭代要做这么几件事:
- 1. 新增弱分类器WeakClassifier(i)与弱分类器权重alpha(i)
- 2. 通过数据集data与数据权重W(i)训练弱分类器WeakClassifier(i),并得出其分类错误率,以此计算出其弱分类器权重alpha(i)
- 3. 通过加权投票表决的方法,让所有弱分类器进行加权投票表决的方法得到最终预测输出,计算最终分类错误率,如果最终错误率低于设定阈值(比如5%),那么迭代结束;如果最终错误率高于设定阈值,那么更新数据权重得到W(i+1)
Python3的实现过程
首先看一下实验结果:
8*8的图片识别数字,正确率达到90%,速度也快。值得学习一下
(1)训练数据测试数据的获取
数据集取自sklearn中的手写数字datasets
选择两个数字1和8的图片(大小8*8),并将他们的标签设置为1和-1,训练一个二分类的分类器
训练集和测试集之间没有交集,数量都是178个
(2)开始训练
创建一个Adaboos对象,指定参数(弱分类器数量n_clf=5),进入fit函数,传入训练数据
初始化样本权重w
进入for循环,遍历每个弱分类器(再次出现蓝字的时候表明循环结束)
创建弱分类器——决策树(其实就是一个二分类器)
clf = DecisionStump()遍历64个特征(一次处理178个样本的值),寻找哪一个特征分类效果最好,以及最优分类阈值(计算分类误差的时候考虑了样本权重(代码62行)),记录在clf中
for feature_i in range(n_features):
建立好一个clf后
循环结束
根据这个clf的分类误差,计算它在强分类器中的权重
循环结束clf.alpha = 0.5 * math.log((1.0 - min_error) / (min_error + 1e-10))
计算样本权重(看基本知识中的公式)
# Set all predictions to '1' initially predictions = np.ones(np.shape(y)) # The indexes where the sample values are below threshold negative_idx = (clf.polarity * X[:, clf.feature_index] < clf.polarity * clf.threshold) # Label those as '-1' predictions[negative_idx] = -1 # Calculate new weights # Missclassified samples gets larger weights and correctly classified samples smaller w *= np.exp(-clf.alpha * y * predictions) # Normalize to one w /= np.sum(w)
保存这个clf到self.clfs中
python3中的技术
内容顺序按照代码调试过程中出现的顺序,包含所有使用到的知识点,并做一点点扩展
(1)ndarray
(1)ndarray最基本的定义方式
(2)这是(1)中定义的ndarray的转置
(3)shape=(4,3),4是指这个ndarray的最外面的第一层的'[]'中的元素的数量,3是第二层,以此类推
(4)先行后列,行代表第一层的元素,列代表第二层
(2)np的一些函数
数组拼接点击查看详细内容
- np.append()
numpy提供了numpy.append(arr, values, axis=None)函数。对于参数规定,要么一个数组和一个数值;要么两个数组,不能三个及以上数组直接append拼接。append函数返回的始终是一个一维数组。
numpy的数组没有动态改变大小的功能,numpy.append()函数每次都会重新分配整个数组,并把原来的数组复制到新数组中。
- np.concatenate()
numpy提供了numpy.concatenate((a1,a2,...), axis=0)函数。能够一次完成多个数组的拼接。其中a1,a2,...是数组类型的参数
拼接shpae=[2,3][2,3]的两个数组,axis=0的时候拼接的是最外层,得到的结果的shape是[4,3],4是2+2的结果;axis=1的时候拼接的是第二层,得到的结果的shape是[2,6],6是3+3的结果;
效率问题有疑点,普遍认为numpy.concatenate效率高,不过实验的时候有异议。
- np.where()
- np.expand_dims
expand_dims(a, axis)
针对的是a的shape,结果就是返回一个a的一个拷贝a‘,不过a’在axis的维度上插入一个1。例如 原本shape为 (2,3),当axis=0,则shape变为(1,2,3),当axis=1则shape变为(2,1,3)
- np.unique()
(3)python中的类
这里有一些例子
self在类的函数定义时需要传入,但是在调用时会自动传入。
self的名字并不是规定死的,但是最好还是按照约定是用self
self总是指调用时的类的实例。
class 类名(父类名)
self指向子类实例,所以实现了多态
创建对象时会进入子类的__init__(),如果子类没有重写父类的__init__,就会进入父类的