最近在做多分類器的集成(ensemble),主要有bagging和boosting,這篇文章主要講的是分類,採用的分類器屬於強分類器,有隨機森林(RandomForestClassifier)、xgb(xgboost)、決策樹(DecisionTreeClassifier)、邏輯斯特迴歸(LogisticRegression)以及梯度下降boost(GradientBoostingClassifier),目的是實驗強分類器的集成對結果的精度是否有所提高。
一、bagging
每個分類器的權重一樣
- 從初始訓練集取出n個訓練樣本(可放回取樣)
- 每個訓練集訓練一個分類器,一共可以得到n個模型
- 將每個模型預測得出的結果進行voting(多數表決),即少數服從多數
二、boosting
是一種將弱分類器集成的方法,這裏介紹adaboost算法,是boosting系列算法中的一種,跟bagging不同的是,它給不同的分類器賦予不同的權重,它的基分類器可以是同類分類器也可以是不同的分類器。
運行過程是:給每一個樣本賦予權重D,初始的樣本權重是相等的。訓練後計算分類器的錯誤率,根據錯誤率ε對樣本的權重進行調整(分類正確的樣本權重會降低,分類錯誤的樣本權重會上升),再進行二次、三次...訓練,最終給不同的 分類器分配不同的權重alpha(分類器的錯誤率低則權重高)
這裏要注意的是調整樣本權重是爲了訓練模型,每次更新完權重就進行下一次的迭代訓練
分類器權重:alpha=0.5*ln(1-ε/max(ε,1e-16))
更新樣本權重: 如果某個樣本被正確分類,那麼權重更新爲:
D(m+1,i)=D(m,i)*exp(-alpha)/sum(D)
如果某個樣本被錯誤分類,那麼權重更新爲:
D(m+1,i)=D(m,i)*exp(alpha)/sum(D)
三、基於不同分類器的boosting算法
注意:
- 迭代過程樣本權重更新用於訓練模型
- 模型訓練中,要更新權重之前要計算錯誤率,將用於訓練的樣本再進行計算錯誤率,結果是沒什麼意義的,所以這裏訓練過程分爲訓練集和測試集。
- 由D更新樣本的公式,分類正確的樣本和錯誤的樣本給予不同的權重。由第2我們可以得知這裏的權重更新是訓練集的權重更新,當我們知道測試集的分類結果後我們得出測試集的樣本更新是沒有意義的。所以我們需要將訓練集再次預測,得出該模型下訓練集的分類情況,由此來更新訓練集的樣本權重。綜上,訓練集的預測是爲了更新樣本,而訓練集的預測是爲了獲取錯誤率。
- 最後得出不同分類器的預測結果,以及分類器的權重,得出最後的結果,計算準確率
代碼如下:
from sklearn.cross_validation import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.ensemble import RandomForestClassifier
from sklearn import cross_validation
import xgboost
from sklearn.tree import DecisionTreeClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import GradientBoostingClassifier
def split_data(feat, labels):
'''
劃分訓練集和測試集
'''
x_train, x_test, y_train, y_test = train_test_split(feat, labels)
return x_train, x_test, y_train, y_test
def init_classifier():
'''
分類器的初始化構造
'''
clf1 = RandomForestClassifier()
clf2 = xgboost.XGBClassifier()
clf3 = DecisionTreeClassifier()
clf4 = LogisticRegression()
clf5 = GradientBoostingClassifier()
return clf1, clf2, clf3, clf4, clf5
def boosting_clf(num, data1, labels1, clf, data2):
'''
分類器clf的adaboost算法
param:
num:訓練迭代次數
data1:數據集
labels1:標籤
data2:最終的測試集
return:
alpha:分類器的權重
pre:對最終測試集的測試結果
'''
#劃分訓練集和測試集
x_train, x_test, y_train, y_test = train_test_split(data1, labels1, test_size=0.3)
#剛開始樣本權重是均值
w = np.ones(len(x_train)) / len(x_train)
#定義最大準確率
max_acc = 0
#定義分類器最終的alpha
result_alpha = 0
#要保存那個結果最好的分類器了,只要保存他的即可
best_w = np.zeros(len(x_train))
#分類器訓練
for i in range(num):
clf.fit(x_train, y_train, sample_weight=w)
#預測
#訓練集的預測用於更新w
pre0 = clf.predict(x_train)
#測試集上的預測用於修改alpha
pre1 = clf.predict(x_test)
#將y_test轉換爲array類型
tt = y_train.values.reshape((1, len(y_train)))[0]
#相同的爲0,不同的爲1,計算訓練集上的miss
miss = [int(t) for t in (pre0 != tt)]
#計算測試集上的準確率
acc = accuracy_score(pre1, y_test)
#計算alpha
alpha = 0.5*(np.log((acc)/(1-acc)))
#在訓練集上更新權重
w = np.multiply(w,np.exp([-alpha * s for s in miss]))
if acc > max_acc:
max_acc = acc
result_alpha = alpha
best_w = w
#訓練完畢
#重新將訓練結果進行訓練(因爲不確定最優的那個結果一定是最後一次訓練的分類器)
clf.fit(x_train, y_train, sample_weight=best_w)
pre = clf.predict(data2)
return result_alpha, pre
def train(feat):
'''
輸入特徵集進行訓練
返回準確率
'''
data1, data2, labels1, labels2 = split_data(feat, labels)
clf1, clf2, clf3, clf4, clf5 = init_classifier()
#訓練2個分類器
a1, p1= boosting_clf(400, data1, labels1, clf1, data2)
a2, p2= boosting_clf(400, data1, labels1, clf2, data2)
#歸一化不同分類器的權重
alp1 = a1 / (a1+a2)
alp2 = a2 / (a1+a2)
#計算最終的預測值
pre = alp1*p1 + alp2*p2
#將預測值四捨五入
pre = np.round(pre)
#計算準確率
acc = accuracy_score(pre, labels2)
return acc
if __name__ == "main":
acc = train(color)
print(acc)
通過train()裏面調用的boosting_clf可以更改分類器,同時要修改alpha的計算,color爲圖片的color特徵,傳入color的特徵集後,得到的準確率:
迭代次數爲200:準確率爲0.7070484581497798
迭代次數爲300:準確率爲0.7158590308370044
迭代次數爲400:準確率爲0.7312775330396476
迭代次數爲500:準確率爲0.6872246696035242