集成學(xué)習(xí)
???簡(jiǎn)單來(lái)說(shuō),集成學(xué)習(xí)就是將一組個(gè)體學(xué)習(xí)器結(jié)合起來(lái),通過(guò)某種策略,將其結(jié)合成一個(gè)總學(xué)習(xí)器來(lái)完成相應(yīng)任務(wù);集成學(xué)習(xí)是為了得到比單一學(xué)習(xí)器更好的泛化性能。主要分為兩種類型:若每個(gè)個(gè)體學(xué)習(xí)器是通過(guò)同一算法得到,則稱為同質(zhì),每個(gè)各體學(xué)習(xí)器稱為基學(xué)習(xí)器;若每個(gè)個(gè)體學(xué)習(xí)器是由不同算法得到,則稱為異質(zhì),個(gè)體學(xué)習(xí)器也可稱為組件學(xué)習(xí)器。
???集成學(xué)習(xí)的一個(gè)核心是:如何產(chǎn)生并結(jié)合“好而不同”的個(gè)體學(xué)習(xí)器。下面是西瓜書里,一個(gè)關(guān)于集成學(xué)習(xí)的直觀舉例,像下面有三種集成學(xué)習(xí)的情況,前兩種情況的個(gè)體學(xué)習(xí)器都是66%的準(zhǔn)確率,可是第一種情況個(gè)體學(xué)習(xí)器之前存在差距,因此集成后效果得到提高;而第二種情況,個(gè)體學(xué)習(xí)器由于之間沒(méi)有差距,因此集成后效果沒(méi)有提高;而第三種因?yàn)閭€(gè)體學(xué)習(xí)器不夠好,因此集成后反而沒(méi)有提高。

集成學(xué)習(xí)的簡(jiǎn)單數(shù)學(xué)解釋
???下面是關(guān)于集成學(xué)習(xí)的一個(gè)簡(jiǎn)單分析:一個(gè)二分類問(wèn)題和其實(shí)際對(duì)應(yīng)函數(shù)
;假設(shè)每個(gè)基分類器
的錯(cuò)誤率為
,即:
通過(guò)投票法集成T個(gè)基本分類器,即:
假設(shè)每個(gè)基分類器
錯(cuò)誤率相互獨(dú)立,那么:
上述公式的第一行可通過(guò)排列組合知識(shí)來(lái)解釋;第二行的不等式是利用Hoeffding不等式所推出得知。上述公式隨著T的增加,其錯(cuò)誤率則不斷的下降;這意味著當(dāng)個(gè)體分類數(shù)目越多,其集成后分類錯(cuò)誤率則越低。
???集成學(xué)習(xí)的方法主要分為兩大類:第一類是串行序列化方法,先從初始訓(xùn)練集得到一個(gè)基學(xué)習(xí)器,然后再調(diào)整訓(xùn)練樣本分布,再訓(xùn)練下一個(gè)基學(xué)習(xí)器,學(xué)習(xí)器之間存在較強(qiáng)的依賴關(guān)系;第二類是并行化方法。第一類的代表是boosting,第二類是bagging和隨機(jī)森林。
boosting
???boosting是一種串行序列化方法,先從初始訓(xùn)練集得到一個(gè)基學(xué)習(xí)器,然后再調(diào)整訓(xùn)練樣本分布,再訓(xùn)練下一個(gè)基學(xué)習(xí)器,學(xué)習(xí)器之間存在較強(qiáng)的依賴關(guān)系;其中AdaBoost就是其中的代表算法。下面是AdaBoost算法的整體流程:
Adaboost(訓(xùn)練集D, 基學(xué)習(xí)算法b, 迭代次數(shù)T){
初始化訓(xùn)練集D的權(quán)重分布D_1(x) = 1 / m
for t = 1 to T {
ht = b(D, D_t) #根據(jù)數(shù)據(jù)集D與數(shù)據(jù)的權(quán)重分布D_t生成基學(xué)習(xí)器ht
計(jì)算h_t的錯(cuò)誤率p
if p > 0.5
break
更新當(dāng)前基學(xué)習(xí)器ht的權(quán)重a_t
更新訓(xùn)練集D的權(quán)重分布D_t+1
}
返回基學(xué)習(xí)器的加權(quán)和:H(x)
}
AdaBoost的優(yōu)化目標(biāo)
???可以看到AdaBoost算法是一個(gè)迭代優(yōu)化算法,該算法的優(yōu)化目標(biāo)是最小化指數(shù)損失函數(shù)的期望,假設(shè)問(wèn)題是解決一個(gè)二分類問(wèn)題。
然后損失函數(shù)對(duì)
進(jìn)行求導(dǎo)可得:
令上式取零解后,可得:
進(jìn)一步可得到:
上述過(guò)程說(shuō)明
達(dá)到貝葉斯最優(yōu)錯(cuò)誤率,即最小化上述指數(shù)損失函數(shù)的期望,也可將錯(cuò)誤率最小化;并且該損失函數(shù)更具比較好的數(shù)學(xué)性質(zhì)。因此AdaBoost的優(yōu)化目標(biāo)是:最小化指數(shù)損失函數(shù)的期望。
AdaBoost的參數(shù)更新
???損失函數(shù)中,其中
的定義是:
而基分類器
是由關(guān)于數(shù)據(jù)集的權(quán)重
與數(shù)據(jù)集
共同生成,因此AdaBoost算法中,需要更新的參數(shù)為:
和
。
???關(guān)于,將t時(shí)刻的分類器代入損失函數(shù)中可得:
求上述式子關(guān)于
的偏導(dǎo),可得:
取上式的零解,可得:
這就是
的更新公式。
??? 下面是關(guān)于AdaBoost算法中,是對(duì)
錯(cuò)判的數(shù)據(jù)極可能的關(guān)注的一個(gè)證明,使得基學(xué)習(xí)器
盡可能的糾正
的錯(cuò)誤,即最小化:
對(duì)上述式子后半部分進(jìn)行泰勒展開(kāi),可得:
那么想
可以糾正更多錯(cuò)誤,則可以最小化損失函數(shù),即:
設(shè)分布
為:
由數(shù)學(xué)期望定義,上式等價(jià)于:
個(gè)人對(duì)于上式第一行的理解是,左半部分是計(jì)算一個(gè)基于分布D的一個(gè)數(shù)學(xué)期望,簡(jiǎn)單來(lái)寫就是:分布D
取值,而再結(jié)合分布
的定義,就變成右半部的隨機(jī)變量f(x)h(x)關(guān)于分布
的數(shù)學(xué)期望。
???上面的過(guò)程是關(guān)于基分類器是對(duì)之前分布錯(cuò)誤的一個(gè)調(diào)整后的分類器,使得
將在分布
下最小化誤差。
???關(guān)于分布的更新,則可從式子出發(fā):
???總的來(lái)說(shuō),AdaBoost算法最主要的是下面兩個(gè)式子:
AdaBoost的實(shí)現(xiàn)
???這里關(guān)于AdatBoost的實(shí)現(xiàn),是參考《機(jī)器學(xué)習(xí)實(shí)戰(zhàn)》里面的實(shí)現(xiàn)。該實(shí)現(xiàn)中使用的弱分類器是決策樹(shù)樁(decision stump),其是單層決策樹(shù),既只通過(guò)某個(gè)特征的某個(gè)特征值的大于小于來(lái)進(jìn)行分類。
???下面這段代碼是關(guān)于決策樹(shù)樁的分類,其實(shí)只是根據(jù)某個(gè)特征的某個(gè)值進(jìn)行二分:
def stumpClassify(dataset, index, value, ops):
m, n = dataset.shape
res = np.ones((m))
#lt代表小于value值的為負(fù)類,gt代表大于value值的為負(fù)類
if ops == 'lt':
res[ np.where( dataset[:, index] <= value )[0] ] = -1.0
elif ops== 'gt':
res[ np.where( dataset[:, index] > value )[0] ] = -1.0
return res
這一段是關(guān)于如何建立一個(gè)決策樹(shù)樁,通過(guò)遍歷所有特征的特征值,選擇其中帶權(quán)誤差率(分布D的作用主要是計(jì)算誤差率)最小的作為建立的決策樹(shù)樁。:
def buildStump(dataset, D):
m, n = dataset.shape
bestStump = {}
bestClassEst = np.zeros(m)
numSteps = 10.0
min_err = np.inf
for i in range( n - 1 ):
#將值范圍分成numSteps等份,再以該等份的值作為分類的值
min_value = np.min( dataset[:, i] ); max_value = np.max( dataset[:, i] )
step_size = (max_value - min_value) / numSteps
for j in range(-1, int(numSteps) + 1):
for o in ['lt', 'gt']:
value = min_value + float(j) * step_size
predictions = stumpClassify(dataset, i, value, o)
mistake = (predictions != dataset[:, -1] )
weight_err = np.dot(D, mistake)
if weight_err < min_err:
min_err = weight_err
bestClassEst = predictions.copy()
bestStump['idx'] = i
bestStump['val'] = value
bestStump['ops'] = o
return bestStump, min_err, bestClassEst
下面這段代碼是AdaBoost的主體:
def AdaBoot(dataset, numIter=40):
bases = []
m, n = dataset.shape
D = np.ones( m ) / m
acc_res = np.zeros( m )
for i in range( numIter ):
#根據(jù)分布D和數(shù)據(jù)集,建立基分類器
stump, err_rate, classEnt = buildStump(dataset, D)
#若單個(gè)基分類器錯(cuò)誤率大于0.5拋棄并退出循環(huán)
if err_rate > 0.5:
break
#更新基分類器權(quán)重
alpha = np.log( (1.0 - err_rate) / np.maximum(err_rate, 1e-6) ) * 0.5
stump['alpha'] = alpha
bases.append( stump )
#更新下一次的權(quán)重分布D
D = D * np.exp( -1.0 * classEnt * dataset[:, -1] * alpha ) / np.sum( D )
#計(jì)算當(dāng)前集成后的分類器的錯(cuò)誤率
acc_res += alpha * classEnt
acc_err = np.mean(np.sign( acc_res ) != dataset[:, -1])
ji
#若集成后的分類器已經(jīng)達(dá)到零差錯(cuò),則無(wú)需繼續(xù)進(jìn)行下去
if acc_err == 0.0:
break
return bases
而到實(shí)際用于分類時(shí),只需遍歷base中的分類器,將分類結(jié)果加權(quán)求和即可。
sklearn中的AdaBoost
???在sklearn中,AdaBoost的使用與其他模型類似;其默認(rèn)的base_estimator是一層的決策樹(shù),而具體的實(shí)現(xiàn)算法有:SAMME和SAMME.R,SAMME是以分類的類別作為調(diào)整權(quán)值分布,而SAMME.R是以分類的類別概率來(lái)調(diào)整權(quán)值分布。