注:adaboost可以做分类也可以做回归,本篇以构建二分类模型为例,通过手写代码,加深对算法原理与流程的理解。
有监督的分类算法
- 分类器的错误率:
- 弱分类器的权重:
注:错误率越高,该分类器的权重越小
- 正确分类的样本权重:
- 错误分类的样本权重:
注:初始化样本权重是相等的;如果该样本被错误分类,则在下一轮该样本的权重被提高
def classify(xmat,i,threshold,mark):
'''
函数功能:单层决策树分类函数
参数说明:
xmat:特征矩阵
i:第i个特征
threshold:切分点的特征值
mark:标志,取值'less_than(含相当)'或'greater_than'
返回:
label:二分类结果,暂用1和-1表示,这样做有两个好处,详见下面。
'''
label=np.ones((xmat.shape[0],1))
if mark=='less_than':
label[xmat[:,i] <= threshold]=-1 #注:不能是0。
else:
label[xmat[:,i] > threshold]=-1
return label
def best_tree_stump(xmat,ymat,W):
'''
函数功能:寻找最佳的单层决策树
参数说明:
xmat:特征矩阵
ymat:标签矩阵
W:样本权重
返回:
beststump:最佳单层决策树,字典格式
minE:最小误差
bestlabel:最佳的分类结果
'''
N,M=xmat.shape
steps=10 #初始化步数
beststump={}
bestlabel=np.mat(np.zeros((N,1)))
minE=np.inf #初始化为正无穷大
#遍历每个特征
for i in range(M):
min_value=xmat[:,i].min()
max_value=xmat[:,i].max()
stepsize=(max_value-min_value)/steps #计算步长
for j in range(-1,int(steps)+1):
for mark in ['less_than','greater_than']:
threshold=(min_value+j*stepsize)
label=classify(xmat,i,threshold,mark)
error=np.mat(np.ones((N,1))) #初始化误差矩阵
error[label==ymat]=0 #分类正确,则误差为零
sum_error=W.T * error #计算总误差值
if sum_error < minE:
minE=sum_error
bestlabel=label.copy()
beststump['feature_index']=i
beststump['feature_value_threshold']=threshold
beststump['feature_mark']=mark
return beststump,minE,bestlabel
def adaboost_train(xmat,ymat,max_iter=50):
'''
函数功能:生成各弱分类器及其决策权重
返回:
weakclassify:弱分类器集,列表格式
pre_weighted_label:类别预测值
'''
N,M=xmat.shape
W=np.mat(np.ones((N,1)))/N #初始化
pre_weighted_label=np.mat(np.zeros((N,1))) #初始化
weakclassify=[]
for i in range(max_iter):
stump,err,label=best_tree_stump(xmat,ymat,W)
alpha=float( np.log((1-err) / max(err,1e-16))/2 ) #第i个弱分类的权重
stump['alpha']=np.round(alpha,2)
weakclassify.append(stump)
#更新权重
expon=np.multiply(-1* alpha * ymat,label) #正确分类,取负alpha,错误分类,取正alpha。(好处一,方便求取正负alpha)
W=np.multiply(W,np.exp(expon))
W=W/ W.sum()
pre_weighted_label += alpha*label
#计算误差
aggErr=np.multiply(np.sign(pre_weighted_label)!=ymat,np.ones((N,1)))
errRate=aggErr.sum()/N
if errRate==0:break #误差为零,退出循环
return weakclassify,pre_weighted_label
def adaboostclassify(newdataset,weakclassify):
'''
函数功能:二分类预测
参数说明:
newdataset:未知样本
weakclassify:已训练好的分类器
返回:分类标签
'''
newdatamat=np.mat(newdataset)
N=newdatamat.shape[0]
pre_weighted_label=np.mat(np.zeros((N,1)))
#遍历所有分类器
for i in range(len(weakclassify)):
classest=classify(newdatamat,weakclassify[i]['feature_index'],weakclassify[i]['feature_value_threshold'],weakclassify[i]['feature_mark'])
pre_weighted_label +=classest*weakclassify[i]['alpha'] #(好处2,方便直接求决策权重)
return np.sign(pre_weighted_label) # 大于零,说明预测为1的权重之和,大于预测为-1的权重之和,则返回1;小于零,则返回0.
from sklearn.ensemble import AdaBoostClassifier
from sklearn.ensemble import AdaBoostRegressor
参考:http://edu.cda.cn/course/966