提升算法是将一组弱分类器组合成强分类器的算法,大多数的提升算法都是改变训练数据的概率分布(或权值),针对不用的训练数据训练弱分类器学习,最后再组合弱分类器成为一个强分类器。
对于提速算法,需要解决两个问题:
AdaBoost提升算法主要做法:
具体算法为:
有训练集 T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x N , y N } T = \{(x_1,y_1),(x_2,y_2),...,(x_N,y_N\} T={(x1,y1),(x2,y2),...,(xN,yN},其中 y = { − 1 , + 1 } y=\{-1,+1\} y={−1,+1}
首先初始化每个样本的权值为样本总数的倒数,即:
D 1 = ( w 11 , . . . , w 1 , i , . . . , w 1 , N ) , w 1 , N = 1 N D_1 = (w_{11},...,w_{1,i},...,w_{1,N}),\ \ \ w_{1,N}=\frac{1}{N} D1=(w11,...,w1,i,...,w1,N), w1,N=N1
假设我们希望学习 M M M个弱分类器, m = 1 , 2 , . . . , . M m = 1,2,...,.M m=1,2,...,.M,有如下计算步骤:
G m ( x ) : X → { − 1 , 1 } G_m(x):\mathcal{X}→\{-1,1\} Gm(x):X→{−1,1}
e m = ∑ i = 1 N w m i I ( G m ( x i ) ≠ y i ) e_m = \displaystyle\sum_{i=1}^Nw_{mi}I(G_m(x_i)≠y_i) em=i=1∑NwmiI(Gm(xi)=yi)
注意这里是误分类率,即当前分类器分类错误的个数并且乘上当前样本的权值 w m i w_{mi} wmi。更要注意的是,这里的 G m ( x ) G_m( x ) Gm(x)是单个分类器,不要使用当前积累的总分类器 f m ( x ) f_m(x) fm(x)去预测
α m = 1 2 l o g 1 − e m e m \alpha_m = \frac{1}{2}log\frac{1-e_m}{e_m} αm=21logem1−em
这个式子的意义在于,当 e m > 0.5 e_m>0.5 em>0.5时 α m < 0 \alpha_m<0 αm<0,即误差率高时呈负面作用,而 e m < 0.5 e_m<0.5 em<0.5时 α m > 0 \alpha_m>0 αm>0且 e m e_m em越小 α m \alpha_m αm越大,表明误差率越小该分类器对分类的贡献越大,在组合时“话语权”更大。
更新训练数据集的权值分布
w m + 1 , i = w m i Z m e − α m y i G m ( x i ) \Large w_{m+1,i} = \frac{w_{mi}}{Z_m}e^{-\alpha_my_iG_m(x_i)} wm+1,i=Zmwmie−αmyiGm(xi)
其中 Z Z Z是规范化因子:
Z m = ∑ i = 1 N w m i e − α m y i G m ( x i ) \Large Z_m = \displaystyle\sum_{i=1}^Nw_{mi}e^{-\alpha_my_iG_m(x_i)} Zm=i=1∑Nwmie−αmyiGm(xi)
这里 y i ∗ G m ( x i ) y_i*G_m(x_i) yi∗Gm(xi)表示的是当分类器预测正确时结果为1,分类错误时结果为-1
组合当前的弱分类器:
f m ( x ) = ∑ i = 1 m α m G m ( x ) f_m(x) = \displaystyle\sum_{i=1}^m\alpha_mG_m(x) fm(x)=i=1∑mαmGm(x)
一直循环上述步骤,直到组合出达到标准的强分类器(比如误分类率为0),最后得到的强分类器:
G ( x ) = s i g n ( f ( x ) ) = ∑ m = 1 M α m G m ( x ) G(x) = sign(f(x)) = \displaystyle\sum_{m=1}^M\alpha_mG_m(x) G(x)=sign(f(x))=m=1∑MαmGm(x)
这里 s i g n ( x ) sign(x) sign(x)是指示函数,将 f ( x ) f(x) f(x)的值映射到 { 1 , − 1 } \{1,-1\} {1,−1}
这里以李航《统计学习方法》第158页例8.1为例,简要实现Adaboost算法
在这个例子中,分类器为 x < v xflag
区分;强分类器的标准是误分类点个数为0
import numpy as np
# 计算单个分类器
# 按《统计学习方法》中的例子,该出分类器为寻找切分点切分左右进行分类
def cal_G(data, label ,weights):
best_point = -1
best_error = float('inf') #初始化误分类率
best_flag = 0 #是小于切分点为正还是大于切分点为正
for i in range(len(data)-1): #n条数据有n-1个切分点
point = (data[i] + data[i+1]) / 2
for flag in [-1, 1]: #两种切分方向
error = 0
for j in range(len(data)):
if predict(data[j],point, flag) != label[j]:
error += weights[j]
if error < best_error:
best_point = point
best_error = error
best_flag = flag
# 选出切分点后,计算误差率e和系数α
e = best_error
a = 1/2 * np.log((1-e)/e)
# 调整权值分布
#计算Z
Z = 0
for i in range(len(data)):
Z += weights[i] * np.exp(-a*label[i]*predict(data[i], best_point, best_flag))
#更新权值
for i in range(len(weights)):
weights[i] = weights[i] * np.exp(-a*label[i]*predict(data[i],best_point, best_flag)) / Z
return a, best_point, weights, best_flag
#不断将弱分类器组合成强分类器
def adaboost(data, label, weight):
a, g, w, f = cal_G(data, label, weight) #先进行一轮
A = [a] #分类器的系数
G = [g] #所有的分类器
F = [f] #切分点朝向
all_e = final_predict(data, label, A, G ,F) #整体分类器误分类点个数
while all_e != 0 :
a, g, w, f = cal_G(data, label, w)
A.append(a)
G.append(g)
F.append(f)
all_e = final_predict(data, label, A, G, F)
return A, G, F
#一个切分点的预测值
def predict(x, point,flag):
# 小于point为正例子时
if flag == 1:
return 1 if x < point else -1
if flag == -1:
return -1 if x < point else 1
#对于组合分类器的预测
def final_predict(data, label, A, G, F):
error = 0
for i,x in enumerate(data):
res = 0
for j in range(len(G)):
res += A[j] * predict(x, G[j], F[j])
res = 1 if res > 0 else -1
if res != label[i]:
error += 1
return error #总体误分类点个数
if __name__ == '__main__':
X = list(np.arange(0,10))
Y = [1,1,1,-1,-1,-1,1,1,1,-1]
weights = [1/len(X)]*len(X) #初试化权值
A, G, F = adaboost(X, Y, weights)
s = ['%.4f'%(A[i]) + '*' + ('(<' if F[i] == 1 else '(>' )+(str(G[i])) + ')' for i in range(len(A))]
print('最终模型为:{}'.format('+'.join(s)))
最后得到的强分类器,与李航《统计学习方法》第160页中得到的结果一致。
其实训练过程也是一样的,大家可以逐步打印。
李航《统计学习方法》第二版