Adaptive basis function models
------七月算法*机器学习笔记
核方法:一个函数可以表示为多个基函数的加权求和
--当时,为线性基函数,这会给模型带来巨大的局限性,因此将输⼊变量的固定的⾮线性函数进⾏线性组合来拟合函数
,为所有数据或部分数据,可认为变量x到每一个数据的距离
核函数,可以看作度量两者之间距离的一个函数
,高斯核
,当(1)式中为对角阵时,可简化为下面的核函数,其中表示对角线元素
,当(1)式中为球形(对角阵,且对角线各元素相等)时,可简化为该式,即svm中的rbf kernel
,余弦相似度,前期的nlp中xi表示一个向量,xij表示wordj在document i中出现的次数。但这样做效果不好:1.stop words是没有区分度的,但将其考虑进来就会影响距离的度量;2.对于有区分度的词,如果在一个document中出现了很多次,相似度就被人为地放大了。所以后来不直接用xij这种方式,而是TF-IDF(term frequency(解决2,针对xij)-inverse document frequency(解决1,针对j))
好的kernel的定义是很难的,因此学者们先后提出:
1.Maximizing likelihood(最大似然估计),指定核函数,但会设置参数,然后使用最大似然估计去估计参数
2.MKL(multiple kernel learning),核函数由多个核加权组成的,主要还是学参数
前面两种方式kernel都是提前定义的,或者说固定不变的,只是学的参数
3.Adaptive basis function model(ABM):,即basis function,它不是人为定义的,而是learned from data!前面提到的CART(classification and regression tree)就是ABM的一种
Boosting
a greedy algorithm for fitting ABM
成熟应用--人脸检测
weak learner(弱学习机):对一定分布的训练样本给出的假设(仅仅强于随机猜测,用简单的比例表示的话正确率50%-60%)
strong learner(强学习机):根据得到的弱学习机和相应的权重给出假设(最大程度符合实际情况,80%以上)
弱学习机-------------boosting------------>强学习机,目标:最小化损失,
boosting算法:
• 首先给出任意一个弱学习算法和训练集 (x1 , y1 ) , ( x2 , y2 ) , ⋯, ( xn,yn ) , xi ∈X, X 表示某个实例空间,在分类问题中是一个带类别标志的集合, yi∈Y = { + 1, - 1}。
•初始化时, Adaboost为训练集指定分布为1 /n, 即每个训练例的权重都相同 为1 /n。
• 接着,调用弱学习算法进行T 次迭代,每次迭代后 按照训练结果更新训练集上的分布,对于训练失败的训练例赋予较大的权重,使得下一次迭代更加关注这些 训练例,从而得到一个预测函数序列h1 , h2 , ⋯, ht ,每个预测函数ht也赋予一个权重, 预测效果好的, 相应的权重越大
• T 次迭代之后,在分类问题中最终的预测函数 H 采用带权重的投票法产生。
• 单个弱学习器的学习准确率不高,经过运用 Boosting 算法之后,最终结果准确率将得到提高。
下面是多种boosting算法,为误差分类率,
Adaboost(指数loss)
对求导并等0得:
初始化:
迭代求解:分别是弱学习机和弱学习机内部元素x的参数
实践中通常添加一个参数=0.1,避免得到的弱学习机过于’强势‘,导致之前的弱学习机影响很小
Adaboost损失函数
,其中定义
对于二元分类,,即相等即同号为1,不等异号为-1,
化简,
,即设定了一个标准,错误分类个数
因此,观察上式,对求偏导时求最小值时,仅与有关,故得
参数
Update:
实现步骤:
1.
2. for do
3. Fit a classifer to the trainning set using weights
4. Compute
5. Compute
6. Update
7. Return ,=0 or 1
– 样本的权重:
• 没有先验知识的情况下,初始的分布应为等概分布,也就是训 练集如果有N个样本,每个样本的分布概率为1/N
• 每次循环后提高错误样本的分布概率,分错样本在训练集中所 占权重增大 使得下一次循环的弱学习机能够集中力量对 这些错误样本进行判断。
– 弱学习机的权重
• 准确率越高的弱学习机权重越高
– 循环控制:损失函数达到最小
• 在强学习机的组合中增加一个加权的弱学习机 使准确率提高,损失函数值减小。
缺点:
– 速度慢,在一定程度上依赖于训练数据集合和弱学习器的选择,训练数据不充足或者弱学习器太过“弱”,都将导致其训练精度的下降。
– Boosting易受到噪声的影响,这是因为它在迭代过程中总是给噪声分配较大的权重,使得这些噪声在以后的迭代中受到更多的关注。
from numpy import *
import numpy as np
from matplotlib import pyplot as plt
def weakClassifier(dataMatrix,dimen,threshVal,threshIneq):#just classify the data,,lt:less than
retArray = ones((shape(dataMatrix)[0],1))
if threshIneq == 'lt':
retArray[dataMatrix[:,dimen] <= threshVal] = -1
else:
retArray[dataMatrix[:,dimen] > threshVal] = -1
return retArray
def BuildweakClassifier(dataArr,classLabels,weight_):
dataMatrix = mat(dataArr)
labelMat = mat(classLabels).T
m,n = shape(dataMatrix)
numSteps = 10.0#阈值划分精确度
bestStump = {}
bestClasEst = mat(zeros((m,1)))
minError = inf #init error sum, to +infinity
for i in range(n):#loop over all dimensions
rangeMin = dataMatrix[:,i].min()#current feature min value
rangeMax = dataMatrix[:,i].max()#max value
stepSize = (rangeMax-rangeMin)/numSteps
for j in range(int(numSteps)+1):#loop over all range in current dimension
for inequal in ['lt', 'gt']: #go over less than and greater than
threshVal = (rangeMin + float(j) * stepSize)#阈值[每个阈值下的错误分类率,取最小error时的那个阈值,作为最终的弱分类器阈值;以及对应的特征作为最佳分类特征,不等式(ineq)阈值左侧还是右侧作为条件存入bestStump字典中]
predictedVals = weakClassifier(dataMatrix,i,threshVal,inequal)#call stump classify with i, j, lessThan
errArr = mat(ones((m,1)))#初始化误差分类率
errArr[predictedVals == labelMat] = 0#分类正确赋值0
weightedError = weight_.T*errArr/np.sum(weight_) #calc total error multiplied by weight_
#print "split: dim %d, thresh %.2f, thresh ineqal: %s, the weighted error is %.3f" % (i, threshVal, inequal, weightedError)
if weightedError < minError:
minError = weightedError
bestClasEst = predictedVals.copy()#最小error下的分类结果
bestStump['dims'] = i
bestStump['thresh'] = threshVal
bestStump['ineq'] = inequal
return bestStump,minError,bestClasEst
def adaBoostTrainDS(dataArr,classLabels,numIt=40):
weakClassArr = []
m = shape(dataArr)[0]
weight_ = mat(ones((m,1))/m) #init weight_ to all equal
aggClassEst = mat(zeros((m,1)))
for i in range(numIt):
bestStump,error,classEst = BuildweakClassifier(dataArr,classLabels,weight_)#build Stump
# print ("weight_:",weight_.T)
beta = 0.5*log((1.0-error)/max(error,1e-16))#calc beta, throw in max(error,eps) to account for error=0
# print(float(beta),'((((((((')
bestStump['beta'] = beta
weakClassArr.append(bestStump) #store Stump Params in Array
# print ("classEst: ",classEst)
exp_on = multiply(mat(-1*beta*classLabels).T,classEst) #exponent for weight_ calc, getting messy
weight_ = multiply(weight_,exp(exp_on)) #Calc New weight_ for next iteration
weight_ = weight_/weight_.sum()#标准化,并更新
#calc training error of all classifiers, if this is 0 quit for loop early (use break)
aggClassEst += float(beta)*classEst#强分类器:弱分类器的组合
#print ("aggClassEst: ",aggClassEst.T)
aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T,ones((m,1)))
errorRate = aggErrors.sum()/m#误差分类率达到某一阈值,结束循环
print ("total error: ",errorRate)
if errorRate == 0.0: break
print ("#######################################################" )
print ("Number of Iteration: ",i+1)
return weakClassArr,aggClassEst
def adaClassify(datToClass,classifierArr):
dataMatrix = mat(datToClass)#do stuff similar to last aggClassEst in adaBoostTrainDS
m = shape(dataMatrix)[0]
aggClassEst = mat(zeros((m,1)))
for i in range(len(classifierArr)):
classEst = weakClassifier(dataMatrix,classifierArr[i]['dims'],
classifierArr[i]['thresh'],
classifierArr[i]['ineq'])#call stump classify
aggClassEst += float(classifierArr[i]['beta'])*classEst
#print aggClassEst
return sign(aggClassEst)
if __name__=="__main__":
from sklearn import svm, datasets
iris = datasets.load_iris()
# print ('keys:', iris.keys())
dat = iris.data[0:100,0:2] #only use the first three features
print(dat)
label = iris.target[0:100]
# print(label)
label[label==0]=-1
weakClassArr,aggClassEst = adaBoostTrainDS(dat,label)
print (weakClassArr)
# print(dat[:,weakClassArr[0].get('dims')])
pred = adaClassify(dat,weakClassArr)#
print(pred)