1. 程式人生 > >機器學習之整合學習(三)AdaBoost演算法scikit-learn庫

機器學習之整合學習(三)AdaBoost演算法scikit-learn庫

一、AdaBoost類庫概述

        scikit-learn中AdaBoost類庫比較直接,就是AdaBoostClassifier和AdaBoostRegressor兩個,從名字就可以看出AdaBoostClassifier用於分類,AdaBoostRegressor用於迴歸。

        AdaBoostClassifier使用了兩種AdaBoost分類演算法的實現,SAMME和SAMME.R。而AdaBoostRegressor則使用了Adaboost迴歸演算法Adaboost.R2。

        對Adaboost調參時,主要對兩部分內容進行調參,第一部分是對AdaBoost的框架進行調參, 第二部分是對選擇的弱分類器進行調參。兩者相輔相成。下面就對AdaBoost的兩個類AdaBoostClassifier和AdaBoostRegressor,從這兩方面進行介紹。

二、AdaBoostClassifier和AdaBoostRegressor框架引數

        首先來看看AdaBoostClassifier和AdaBoostRegressor框架引數。兩者大部分框架引數相同,下面一起討論這些引數,兩個類如果有不同點會指出。

1) base_estimator

        AdaBoostClassifier和AdaBoostRegressor都有,即弱分類學習器或者弱迴歸學習器。理論上可以選擇任何一個分類或者回歸學習器,不過需要支援樣本權重。常用的一般是CART決策樹或者神經網路MLP。預設是決策樹,即AdaBoostClassifier預設使用CART分類樹DecisionTreeClassifier,而AdaBoostRegressor預設使用CART迴歸樹DecisionTreeRegressor。另外有一點需要注意,如果選擇的AdaBoostClassifier演算法是SAMME.R,則弱分類學習器還需要支援概率預測,也就是在scikit-learn中弱分類學習器對應的預測方法除了predict還需要有predict_proba。

2) algorithm

        這個引數只有AdaBoostClassifier有。主要原因是scikit-learn實現了兩種Adaboost分類演算法,SAMME和SAMME.R。兩者的主要區別是弱學習器權重的度量,SAMME使用了對樣本集分類效果作為弱學習器權重,而SAMME.R使用了對樣本集分類的預測概率大小來作為弱學習器權重。由於SAMME.R使用了概率度量的連續值,迭代一般比SAMME快,因此AdaBoostClassifier的預設演算法algorithm的值也是SAMME.R。一般使用預設的SAMME.R就夠了,但是要注意的是使用了SAMME.R, 則弱分類學習器引數base_estimator必須限制使用支援概率預測的分類器。SAMME演算法則沒有這個限制。

3) loss

        這個引數只有AdaBoostRegressor有,Adaboost.R2演算法需要用到。有線性‘linear’, 平方‘square’和指數 ‘exponential’三種選擇,預設是線性,一般使用線性就足夠了,除非懷疑這個引數導致擬合程度不好。這個值對應了對第k個弱分類器的中第i個樣本的誤差的處理,即:如果是線性誤差,則;如果是平方誤差,則;如果是指數誤差,則,Ek為訓練集上的最大誤差

4) n_estimators

        AdaBoostClassifier和AdaBoostRegressor都有,就是弱學習器的最大迭代次數,或者說最大的弱學習器的個數。一般來說n_estimators太小,容易欠擬合,n_estimators太大,又容易過擬合,一般選擇一個適中的數值,預設是50。在實際調參的過程中,常常將n_estimators和下面介紹的引數learning_rate一起考慮。

5) learning_rate

        AdaBoostClassifier和AdaBoostRegressor都有,即每個弱學習器的權重縮減係數ν。加上正則化項後,強學習器的迭代公式為。ν的取值範圍為0<ν≤1。對於同樣的訓練集擬合效果,較小的ν意味著需要更多的弱學習器的迭代次數。通常用步長和迭代最大次數一起來決定演算法的擬合效果,所以這兩個引數n_estimators和learning_rate要一起調參。一般來說,可以從一個小一點的ν開始調參,預設是1。

三、AdaBoostClassifier和AdaBoostRegressor弱學習器引數

        這裡再討論下AdaBoostClassifier和AdaBoostRegressor弱學習器引數,由於使用不同的弱學習器,則對應的弱學習器引數各不相同。這裡僅僅討論預設的決策樹弱學習器的引數,即CART分類樹DecisionTreeClassifier和CART迴歸樹DecisionTreeRegressor。

        DecisionTreeClassifier和DecisionTreeRegressor的引數基本類似,這裡只拿出調引數時需要尤其注意的最重要幾個的引數再拿出來說一遍:

1) 劃分時考慮的最大特徵數max_features

        可以使用很多種型別的值,預設是"None",意味著劃分時考慮所有的特徵數;如果是"log2"意味著劃分時最多考慮log2(N)個特徵;如果是"sqrt"或者"auto"意味著劃分時最多考慮sqrt(N)個特徵。如果是整數,代表考慮的特徵絕對數;如果是浮點數,代表考慮特徵百分比,即考慮(百分比xN)取整後的特徵數,其中N為樣本總特徵數。一般來說,如果樣本特徵數不多,比如小於50,用預設的"None"就可以了;如果特徵數非常多,可以靈活使用剛才描述的其他取值來控制劃分時考慮的最大特徵數,以控制決策樹的生成時間。

2) 決策樹最大深max_depth

        預設可以不輸入。如果不輸入的話,決策樹在建立子樹的時候不會限制子樹的深度。一般來說,資料少或者特徵少的時候可以不管這個值。如果模型樣本量多,特徵也多的情況下,推薦限制這個最大深度,具體的取值取決於資料的分佈。常用的可以取值10-100之間。

3) 內部節點再劃分所需最小樣本數min_samples_split

        這個值限制了子樹繼續劃分的條件,如果某節點的樣本數少於min_samples_split,則不會繼續再嘗試選擇最優特徵來進行劃分。 預設是2,如果樣本量不大,不需要管這個值。如果樣本量數量級非常大,則推薦增大這個值。

4) 葉子節點最少樣本數min_samples_leaf

        這個值限制了葉子節點最少的樣本數,如果某葉子節點數目小於樣本數,則會和兄弟節點一起被剪枝。 預設是1,可以輸入最少的樣本數的整數,或者最少樣本數佔樣本總數的百分比。如果樣本量不大,不需要管這個值;如果樣本量數量級非常大,則推薦增大這個值。

5) 葉子節點最小的樣本權重和min_weight_fraction_leaf

        這個值限制了葉子節點所有樣本權重和的最小值,如果小於這個值,則會和兄弟節點一起被剪枝。 預設是0,就是不考慮權重問題。一般來說,如果有較多樣本有缺失值,或者分類樹樣本的分佈類別偏差很大,就會引入樣本權重,這時就要注意這個值了。

6) 最大葉子節點數max_leaf_nodes

        通過限制最大葉子節點數,可以防止過擬合,預設是"None",即不限制最大的葉子節點數。如果加了限制,演算法會建立在最大葉子節點數內最優的決策樹。如果特徵不多,可以不考慮這個值,但是如果特徵分成多的話,可以加以限制,具體的值可以通過交叉驗證得到。

四、AdaBoostClassifier實戰

        這裡用一個具體的例子來講解AdaBoostClassifier的使用。

        首先載入需要的類庫:

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import make_gaussian_quantiles
        接著生成一些隨機資料來做二元分類:
# 生成2維正態分佈,生成的資料按分位數分為兩類,500個樣本,2個樣本特徵,協方差係數為2
X1, y1 = make_gaussian_quantiles(cov=2.0,n_samples=500, n_features=2,n_classes=2, random_state=1)
# 生成2維正態分佈,生成的資料按分位數分為兩類,400個樣本,2個樣本特徵均值都為3,協方差係數為2
X2, y2 = make_gaussian_quantiles(mean=(3, 3), cov=1.5,n_samples=400, n_features=2, n_classes=2, random_state=1)
# 將兩組資料合成一組資料
X = np.concatenate((X1, X2))
y = np.concatenate((y1, - y2 + 1))
        通過視覺化看看分類資料,它有兩個特徵,兩個輸出類別,用顏色區別。
plt.scatter(X[:, 0], X[:, 1], marker='o', c=y)
        輸出為下圖:
        可以看到資料有些混雜,現在用基於決策樹的Adaboost來做分類擬合。
bdt = AdaBoostClassifier(DecisionTreeClassifier(max_depth=2, min_samples_split=20, min_samples_leaf=5), algorithm="SAMME",n_estimators=200, learning_rate=0.8)
bdt.fit(X, y)
        這裡選擇了SAMME演算法,最多200個弱分類器,步長0.8,在實際運用中可能需要通過交叉驗證調參而選擇最好的引數。擬合完了後,用網格圖來看看它擬合的區域。
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),
                     np.arange(y_min, y_max, 0.02))

Z = bdt.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
cs = plt.contourf(xx, yy, Z, cmap=plt.cm.Paired)
plt.scatter(X[:, 0], X[:, 1], marker='o', c=y)
plt.show()
        輸出的圖如下:

        從圖中可以看出,Adaboost的擬合效果還是不錯的,現在看看擬合分數:

print "Score:", bdt.score(X,y)
輸出為:
Score: 0.913333333333
        也就是說擬合訓練集資料的分數還不錯。當然分數高並不一定好,因為可能過擬合。

        現在將最大弱分離器個數從200增加到300,再來看看擬合分數。

bdt = AdaBoostClassifier(DecisionTreeClassifier(max_depth=2, min_samples_split=20, min_samples_leaf=5), algorithm="SAMME",n_estimators=300, learning_rate=0.8)
bdt.fit(X, y)
print "Score:", bdt.score(X,y)
此時的輸出為:
Score: 0.962222222222
        這印證了前面講的,弱分離器個數越多,則擬合程度越好,當然也越容易過擬合。

        現在降低步長,將步長從上面的0.8減少到0.5,再來看看擬合分數。

bdt = AdaBoostClassifier(DecisionTreeClassifier(max_depth=2, min_samples_split=20, min_samples_leaf=5),algorithm="SAMME", n_estimators=300, learning_rate=0.5)
bdt.fit(X, y)
print "Score:", bdt.score(X,y)
此時的輸出為:
Score: 0.894444444444
        可見在同樣的弱分類器的個數情況下,如果減少步長,擬合效果會下降。

        最後看看當弱分類器個數為700,步長為0.7時候的情況:

bdt = AdaBoostClassifier(DecisionTreeClassifier(max_depth=2, min_samples_split=20, min_samples_leaf=5),algorithm="SAMME",n_estimators=600, learning_rate=0.7)
bdt.fit(X, y)
print "Score:", bdt.score(X,y)
此時的輸出為:
Score: 0.961111111111
        此時的擬合分數和最初的300弱分類器,0.8步長的擬合程度相當。也就是說,在這個例子中,如果步長從0.8降到0.7,則弱分類器個數要從300增加到700才能達到類似的擬合效果。