Bagging簡介
Bagging是並行式集成學習的最著名代表,名字是由Bootstrap AGGregatING縮寫而來,看到Bootstrap我們就會聯想到boostrap的隨機模擬法和它對應的樣本獲取方式,它是基於自助採樣法(Boostrap sampleing),Bagging也是同理.給定包含m個樣本的數據集,先隨機抽取一個樣本放入採樣集中,再把該樣本放回,使得下次採樣時該樣本仍有機會被選中,這樣經過m次採樣,我們便從原始是數據集中抽取樣本得到一個數據量同爲m的數據集.說簡單一點就是統計裏的有放回抽樣,且每個樣本被抽取的概率相同,均爲總樣本數分之一.
1)樣本抽取方式
假設一個樣本被抽取的概率是1/m,有:
意味着抽樣次數足夠大時,一個樣本不被抽到的概率爲36.8%,由此可知,初始樣本約有63.2%的樣本出現在採樣集中.這樣我們可以採樣T次,從而得到T個含m個訓練樣本的採樣集,基於每個訓練集樣本訓練一個學習器,最後結合這些學習器的結果,預測總結果,這就是Bagging的大致實現過程,針對最後的預測,Bagging一般採取投票法,若票數相同,則最簡單的方法是是隨機選擇一個,當然也可以進一步考察學習器的投票置信度,或者使用加權投票法等處理最終結果.
2)時間複雜度
這裏基學習器可以選擇DT,LR,NB,SVM,神經網絡等等,假定基學習期的時間複雜度爲O(m),則bagging的複雜度大約爲T(O(m)+O(s)),考慮到採樣與投票的平均過程複雜度O(s)很小,而T通常是一個不太大的常數,所以Bagging的集成與直接使用基學習器算法訓練一個學習器的時間複雜度同階,這說明Bagging是一個很高效的集成學習算法,另外,與AdaBoost只適用於二分類任務不同,Bagging可以用於多分類,迴歸的任務.
3)優缺點
Bagging的個優點是對泛化性能的估計,這得益於自助採樣法,由於訓練只使用了63.2%的樣本,因此剩下約36.8%的樣本可當做測試集來對泛化性能進行‘包外估計’,爲此需記錄每個基學習器所使用的訓練樣本,不放令Dt表示學習器ht實際使用的訓練樣本集,令H_oob(x)表示對有樣本x的包外預測,即測試集不包含數據集中用於訓練的部分:
則Bagging的泛化誤差的包外估計爲:
利用包外估計的優點,我們可以在基學習器的訓練過程中及時調整訓練模型,例如在使用決策樹爲基學習器時,可以根據泛化性能來輔助剪枝,而當使用神經網絡時,則可利用包外樣本來輔助早停從而減少過擬合的風險.
自助採樣法優點比較明顯,但在數學上也有一定的缺陷,重複有放回採樣的道德樣本集改變了數據原有的分佈,因此在一定程度上引入了偏差,對最終的結果預測會造成一定程度的影響.
Bagging實現
這是西瓜書上給出的Bagging僞代碼,我們需要做的很簡單,確定基學習算法,訓練輪數T,利用自助法提取訓練集,最後選擇使誤差最小的y作爲預測樣本的標籤.
導入所需庫
from numpy import *
import matplotlib.pyplot as plt
import random
from sklearn import tree
這裏常用的num庫和mattplot庫就不多贅述了,random庫負責隨機選取樣本實現自助採樣法,sklearn.tree負責使用決策樹作爲基學習器.
讀取數據
def loadDataSet(fileName):#讀取數據
numFeat = len(open(fileName).readline().split('\t'))
dataMat = []; labelMat = []
fr = open(fileName)
for line in fr.readlines():
lineArr =[]
curLine = line.strip().split('\t')
for i in range(numFeat-1):#添加數據
lineArr.append(float(curLine[i]))
dataMat.append(lineArr)
labelMat.append(float(curLine[-1]))#添加數據對應標籤
return dataMat,labelMat
這裏的數據來源《機器學習實戰》第七章的病馬數據,數據包含多匹患有疝氣病的1馬的多項特徵指標,而標籤值對應病馬的死亡率預測,+1對應存活,-1對應死亡,通過決策樹和Bagging,來預測病馬的生存情況.
自助法採樣
def rand_train(dataMat,labelMat):#自助法採樣
len_train = len(labelMat)#獲取樣本1數
train_data = [] ; train_label = []
for i in range(len_train):#抽取樣本數次樣本
index = random.randint(0,len_train-1)#隨機生成樣本索引
train_data.append(dataMat[index])#添加對應數據與標籤
train_label.append(labelMat[index])
return train_data,train_label#返回訓練集與訓練集標籤
通過random.randint隨機生成樣本數範圍內的索引,構造Bagging數據集.
決策樹基學習器
def bagging_by_tree(dataMat,labelMat,t=10):#默認並行生成十個基學習器
test_data,test_label = loadDataSet('horseColicTest2.txt') #獲取測試樣本與標籤
predict_list = []
for i in range(t):#並行生成T個
train_data,train_label = rand_train(dataMat,labelMat)#自主採樣1得到樣本
clf = tree.DecisionTreeClassifier()#初始化決策樹模型
clf.fit(train_data,train_label)#訓練模型
total = []
y_predicted = clf.predict(test_data)#預測數據
total.append(y_predicted)
predict_list.append(total)#結果添加到預測列表中
return predict_list,test_label
默認t=10,即產生十個基學習器,這裏基學習器對應決策樹Tree,通過t次採樣,獲得t個樣本,訓練t個決策樹,將每次預測的結果添加到predict_list中,供之後計算準確率.
彙總結果計算準確率
def calc_error(predict_list,test_label):#計算錯誤率
m,n,k = shape(predict_list)#提取預測集信息
predict_label = sum(predict_list,axis = 0)
predict_label = sign(predict_label)
for i in range(len(predict_label[0])):
if predict_label[0][i] == 0:#如果票數相同,則隨機生成一個標籤
tip = random.randint(0,1)
if tip == 0:
predict_label[0][i] = 1
else:
predict_label[0][i] =-1
error_count = 0#初始化預測錯誤數
for i in range(k):
if predict_label[0][i] != test_label[i]:#判斷預測精度
error_count += 1
error_rate = error_count/k
return error_rate
針對十個基學習器的預測結果,將結果累加,並使用sign函數進行類別預測,對於投票數相同的樣例,按照最簡單的解決方式,隨機選擇一個類別添加,最終統計預測不對的類別,最終計算錯誤率.
主函數
if __name__ == "__main__":
fileName = 'horseColicTraining2.txt'
dataMat,labelMat = loadDataSet(fileName)
train_data,train_label = rand_train(dataMat,labelMat)
predict_list , test_label = bagging_by_tree(dataMat,labelMat)
print("Bagging錯誤率:",calc_error(predict_list,test_label))
運行結果
Bagging錯誤率: 0.26865671641791045
[Finished in 0.9s]
改爲單學習器
def bagging_by_Onetree(dataMat,labelMat,t=10):
test_data,test_label = loadDataSet('horseColicTest2.txt')
train_data,train_label = rand_train(dataMat,labelMat)
clf = tree.DecisionTreeClassifier()
clf.fit(train_data,train_label)
y_predicted = clf.predict(test_data)
error_count = 0
for i in range(67):
if y_predicted[i] != test_label[i]:
error_count += 1
return error_count/67
將bagging_by_tree函數稍微修改,取消學習器個數t,得到單一學習器,訓練樣本,計算錯誤率看看如何.
Bagging錯誤率: 0.22388059701492538
單一學習器錯誤率: 0.3582089552238806
[Finished in 0.9s]
總結
將上述過程多次計算,每次結果都會有所不同,這是因爲隨機抽樣造成的樣本擾動所致,而且針對此樣本集,雖然集成後會提升性能,但Bagging最後的泛性能並不是很理想,因此還有更好的分類模型去預測,這裏只是大概實現Bagging的過程,從而加深集成學習的印象.接下來主要介紹隨機森林RF,隨機森林在Bagging樣本擾動的基礎上,還對屬性進行了隨機選取,大大提升了模型泛化能力,是當前集成學習特別常見的模型.