AdaBoost 属于集成学习算法的一种。集成学习通过构建多个学习任务。结构框架如图所示
集成学习通过多个分类器进行结合,因而大多数情况下拥有较好的泛化性能,以AdaBoost为例,其集成方法各有千秋:可以是同一算法在不同设置下集成;也可以是在不同数据集上集成,一般数据进行抽样训练。
不同的学习器要有一定的准确性,又要有差异性。
如图是Ada的模型:
右边矩形代表不同权重下的数据集(同一数据集)
AdaBoost既可以用于分类问题,也可以用于回归问题。
关于如何推导出算法的简洁公式:(二分类为例)
二分类问题
y∈{1,−1}
和真实的取值函数
f(x)
, 假设基础分类器的错误率为
ϵ
,对于每个分类器
hi(x)
有
原则上若超过半数以上的分类器分类正确,则认为集成分类就是正确的
集成分类器是其线性组合:
而在AdaBoost中,有一种加权线性模型:
其中 αi 为各自分类器的权重。
在分布 D 上,(D为分类器权重向量),定义的最小化损失函数
一个多元复合函数,要求其最小化,则求偏导;这里需要对目标函数也就是 H(x) 求偏导:
H(x)包含取值为1的H1和取值为−1的H2 ,因而链式求偏导过程为:
那么:
∂Lexp(H|D)∂H(x)=∂e−f(x)H(x)∂H(x)=∂e−f1(x)H1(x)∂H1(x)+∂e−f−1(x)H−1(x)∂H(x)=ef1(x)H1(x)[−f1(x)]∂H(x)∂H1(x)+ef−1(x)H−1(x)[−f−1(x)]∂H(x)∂H−1(x)
因为 f1(x)=1 与 f−1(x)=−1 ,代入上式得:
∂Lexp(H|D)∂H(x)=−e−H1(x)P(f(x)=1|x)+eH−1(x)P(f(x)=−1|x)
令其为0求解:
e−H1(x)P(f(x)=1|x)=eH−1(x)P(f(x)=−1|x)⇒eH−1(x)e−H1(x)=P(f(x)=1|x)P(f(x)=−1|x)=eH1(x)+H−1(x)=e2H(x)两边取对数:⇒H(x)=12lnP(f(x)=1|x)P(f(x)=−1|x)
值得注意的是 H(x) 一开始由基于算法初始数据分布而来。
因为:
Ht(x)=αtf(x)
,那么:
算法获得
Ht−1
后,下一轮学习的
ht
将修正
Ht−1
的错误:
对后一项进行二阶泰勒展开:
因为:二阶泰勒展开:
ex=1−x+x22
故上式得: e−f(x)Ht−1(x)∗[1−f(x)ht(x)+f(x)2ht(x)22]
又因为 f(x)2=ht(x)2=1⇒e−f(x)Ht−1(x)∗[1−f(x)ht(x)+12]
argmax=e−f(x)Ht−1(x)f(x)ht(x)
argmax=e−f(x)Ht−1(x)Ex∼D[e−f(x)Ht−1(x)]f(x)ht(x)
那么每次权重
D
的迭代:
下面是代码,公式所有代码实现均在train方法里面:注意一点就是:第一个分类器是基于算法初始数据分布而来(和猜差不多?),此后迭代的生成 ht 和 αt ,而后生成 Dt
class AdaBoost(object):
def __init__(self,data_matrix,labels,iter_nums):
self.X = np.matrix(data_matrix)
self.y = np.matrix(labels)
samples = np.shape(data_matrix)[0]
self.D = np.mat(np.ones((samples,1))/samples)
self.iter = range(iter_nums)
def stumpClassfily(self,data_matrix,dimen,thresh_val,thresh_ineq):
rest_arr = np.ones((np.shape(data_matrix)[0],1))
if thresh_ineq is 'lt':
rest_arr[data_matrix[:,dimen]<=thresh_val] = -1.0
else:
rest_arr[data_matrix[:,dimen]>thresh_val] = -1.0
return rest_arr
def buildStump(self):
samples,features = np.shape(self.X)
num_steps = 10
best_stump = {}
best_class_estimate = np.mat(np.zeros((samples,1)))
min_error = np.inf
for i in range(features):
range_min = self.X[:,i].min()
range_max = self.X[:,i].max()
step_size = (range_max-range_min)/num_steps
for j in range(-1,num_steps+1):
for inequal in ['lt','gt']:
thresh_val = (range_min+float(j)*step_size)
predict_val = self.stumpClassfily(self.X,i,thresh_val,inequal)
error_matrix = np.matrix(np.ones((samples,1)))
error_matrix[predict_val==self.y.T] = 0
weight_error = self.D.T * error_matrix
if weight_error < min_error:
min_error = weight_error
best_class_estimate = predict_val.copy()
best_stump['dim'] = i
best_stump['thresh'] = thresh_val
best_stump['ineq'] = inequal
return best_stump,min_error,best_class_estimate
def train(self):
weak_class_arr = []
samples = np.shape(self.X)[0]
aggravete_class_est = np.mat(np.zeros((samples,1)))
for rounds in self.iter:
best_stump,error,class_est = self.buildStump()
alpha = float(0.5*np.log((1.0-error)/max(error,1e-16)))
best_stump['alpha'] = alpha
weak_class_arr.append(best_stump)
expon_loss_func = np.multiply(-1*alpha*self.y.T,class_est)
self.D = np.multiply(self.D,np.exp(expon_loss_func))
self.D = self.D/self.D.sum()
aggravete_class_est += alpha*class_est
agg_errors_matrix = np.multiply(np.sign(aggravete_class_est)!=self.y.T,
np.ones((samples,1)))
error_rate = agg_errors_matrix.sum()/samples
if error_rate is 0.0:break
return weak_class_arr
class Predcitor(AdaBoost):
def __init__(self,data_matrix,classifyer_set):
self.X = data_matrix
self.classifyers = classifyer_set
def predict(self):
samples = np.shape(self.X)[0]
agg_class_est = np.mat(np.zeros((samples,1)))
for classifyer in self.classifyers:
class_est = self.stumpClassfily(self.X,classifyer['dim'],
classifyer['thresh'],
classifyer['ineq'])
agg_class_est += classifyer['alpha']*class_est
return np.sign(agg_class_est)