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 *
def loadSimpData():
datMat = matrix([[ 1. , 2.1],
[ 2. , 1.1],
[ 1.3, 1. ],
[ 1. , 1. ],
[ 2. , 1. ]])
classLabels = [1.0, 1.0, -1.0, -1.0, 1.0]
return datMat,classLabels
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.0
else:
retArray[dataMatrix[:,dimen] > threshVal] = -1.0
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(); rangeMax = dataMatrix[:,i].max();
stepSize = (rangeMax-rangeMin)/numSteps
for j in range(-1,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)
predictedVals = weakClassifier(dataMatrix,i,threshVal,inequal)#call stump classify with i, j, lessThan
errArr = mat(ones((m,1)))
errArr[predictedVals == labelMat] = 0
weightedError = weight_.T*errArr #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()
bestStump['dim'] = 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 = float(0.5*log((1.0-error)/max(error,1e-16)))#calc beta, throw in max(error,eps) to account for error=0
bestStump['beta'] = beta
weakClassArr.append(bestStump) #store Stump Params in Array
#print "classEst: ",classEst.T
expon = multiply(-1*beta*mat(classLabels).T,classEst) #exponent for weight_ calc, getting messy
weight_ = multiply(weight_,exp(expon)) #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 += 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]['dim'],\
classifierArr[i]['thresh'],\
classifierArr[i]['ineq'])#call stump classify
aggClassEst += classifierArr[i]['beta']*classEst
#print aggClassEst
return sign(aggClassEst)
def change_data(x):
x[0:100,0:50]=1
x[0:100,50:] = -1
return x
if __name__=="__main__":
#dat,lab = loadSimpData()
from sklearn import svm, datasets
iris = datasets.load_iris()
print ('type of iris: ', type(iris)) #<class 'sklearn.datasets.base.Bunch'>
print ('keys:', iris.keys()) #['target_names', 'data', 'target', 'DESCR', 'feature_names']
dat = iris.data[0:100,0:3] #only use the first two features
# change data
dat = change_data(dat)
lab = iris.target[0:100]
lab[lab==0]=-1
weakClassArr,aggClassEst = adaBoostTrainDS(dat,lab)
print (weakClassArr)
pred = adaClassify(dat,weakClassArr)