1.提升方法(boosting)的基本思路
提升方法基于思想:一个复杂任务,多个专家的判断进行适当的综合所得出的判断,要比其中任何一个专家单独的判断要好。
即“三个臭皮匠赛过诸葛亮”。一个分类问题,给定训练样本集,比较粗糙的分类规则(弱分类器)要比精确的分类规则(强分类器)容易得多。 提升方法就是从弱学习算法出发,反复学习,得到一系列弱分类器(也称基本分类器),然后组合这些弱分类器,构成一个强分类器。大多数的提升方法都是改变训练数据的概率分布(训练数据的权值分布),基于不同的训练数据分布调用弱学习算法学习一系列的弱分类器。
提升方法(boosting)有很多,最具代表性的是AdaBoosting算法,其中AdaBoosting是Adaptive Boosting的组合。
现在有两个问题摆在眼前:(1)每一轮如何改变训练数据的权值或者概率分布;(2)如何将弱分类器组合成一个强分类器。
AdaBoosting算法的做法是:
(1)提高那些被前一轮弱分类器错误分类样本的权值,而降低那些被正确分类样本的权值。这样做的好处是:那些没有得到正确分类的数据,由于其权值的加大在后一轮弱分类器中受到更大的关注。
(2)采取加权多数表决的方法。具体地就是:加大分类误差率小的弱分类器的权值,可以使其在表决中起较大的作用,减小分类误差率大的弱分类器的权值,这样可以使得其在表决中起较小的作用。
2.AdaBoost算法详解
AdaBoost算法,从训练样本集中学习一系列分类器或者基本分类器,并将这些弱分类器线性组合成为一个强分类器。
输入:训练数据集T={(x1,y1), (x2,y2), ..., (xn, yn)},其中x是实例空间,y是标记集合,yi∈{+1, -1};弱学习算法;
输出:最终分类器G(x)
(1)初始化训练数据的权值分布
注:python code完成此功能
D = np.ones((1,N))/N
或者
D = [1.0/N for e range(N)]
(2)对于m=1,2,...M
(2.1)使用具有权值分布Dm的训练数据集学习,得到基本分类器
Gm(x) :x-->{-1, +1}
(2.2)计算Gm(x)在训练数据集上的分类误差率
数学示例:
训练样本集的标记集合flags:[1, 1, -1, -1, -1]
本次分类后的标记集合G: [1, -1, 1, -1, -1]
则分类错误统计表格为stat: [0, 1, 1, 0, 0],0表示分类正确,1表示分类错误
如果数据的权值分布为D: [p1, p2, p3, p4, p5]
则G(x)在训练数据集上的分类误差率:
e =0*p1 + 1*p2 + 1*p3 + 0*p4 + 0*p5 = p2+p3
python代码示例:
import numpy as np
D = [0.1, 0.2, 0.25, 0.15, 0.3]#数据的权值分布
flags = [1, 1, -1, -1, -1]#训练数据的标记集合
G = [1,-1, 1, -1, -1]#分类器的分类结果
stat = [0, 1, 1, 0, 0]#分类错误统计表,0=分类正确,1=分类错误
e = np.multiply(stat, D).sum() #0.2 + 0.25 = 0.45
print(e) #0.45
上面的stat需要基于flags和G计算得到的,其python代码如下:
#其中stat需要根据flags和G计算得到,如下所示
flags = [1, 1, -1, -1, -1]#训练数据的标记集合
G = [1,-1, 1, -1, -1]#分类器的分类结果
def get_stat(flags, G):
dif_ufunc = lambda gf,of : (gf!=of and [1] or [0])[0]
dif_func = np.frompyfunc(dif_ufunc, 2, 1)
stat = dif_func(flags, G)
print(stat)
get_stat(flags, G) #[0 1 1 0 0]
(2.3)计算Gm(x)的系数
Gm(X)分类器只是最终强分类器的一个弱分类器,需要有自己的一个权值,数学公式中就是Gm(x)的系数αm:
注意这里的对数是自然对数
python代码示例:
e = 0.45
alpha = 0.5*np.log((1-e)/e)
#0.10033534773107562
(2.4)更新训练数据集的权值分布
这里的Zm是权值分布的规范化因子,可以保证所有的权值加起来等于1,即使得权值分布是一个概率分布。
规范化因子的Python代码:
其中alpha是已经算好的分类器的系数,D是当前的权值分布,flags是训练数据的标记集合,G是分类器分类后的标记集合
#规范化因子z
z_ufunc = lambda w,y,g : w*np.exp(-1*alpha*y*g)
z_func = np.frompyfunc(z_ufunc, 3, 1)
z = z_func(D, flags, G).sum()
更新训练数据的权值分布的python代码:
其中alpha是已经算好的分类器的系数,D是当前的权值分布,flags是训练数据的标记集合,G是分类器分类后的标记集合
#更新训练数据的权值分布
w_ufunc = lambda w,y,g : w/z * np.exp(-1*alpha*y*g)
w_func = np.frompyfunc(w_ufunc, 3, 1)
new_D = w_func(D, flags, G)
(3)构建基本分类器的线性组合f(x)
python代码:
base_gen就是一个基本分类器,见上面概念。
根据算法的要求,f(x) = alpha*base_gen(x, v, f1, f2),而下面的Gen存储了所有子分类器f(x)的系数alpha,阈值v,标记{f1, f2}
Gen的元素个数就是子分类器f(x)的个数,每个元素=[alpha, v, f1, f2],可知Gen的存储结构为:
[[alpha, v, f1, f2], #第一个f(x)的
...., #第i个f(x)的
[alpha, v, f1, f2]] #最后一个f(x)的
注:每个f(x)的[alpha, v, f1, f2]是不相同的
#基本分类器 if x<v then f1 elif x>v then f2
base_gen = lambda x,v,f1,f2 : ( x<v and [f1] or [f2])[0]
#分类器f(x)
fx_ufunc = lambda x : sum([g[0]*base_gen(x, g[1], g[2], g[3]) for g in Gen])
fx_func = np.frompyfunc(fx_ufunc, 1, 1)
(4)得到最终分类器sign[f(x)]
python代码示例:
复用f(x)的python代码.