1. 程式人生 > >常用的集成學習方法

常用的集成學習方法

數據競賽 算法 機器學習

集成學習是構建一組基學習器,並將它們綜合作為最終的模型,在很多集成學習模型中,對基學習器的要求很低,集成學習適用於機器學習的幾乎所有的領域:
1、回歸
2、分類
3、推薦
4、排序

集成學習有效的原因
多樣的基學習器可以在不同的模型中取長補短
每個基學習器都犯不同的錯誤,綜合起來犯錯的可能性不大
但是想同的多個基學習器不會帶來任何提升

集成學習示例:
技術分享圖片
例如在上圖中每個線性模型都不能成功將該數據集分類
但是三個線性模型的簡單綜合即可將數據集成功分類,每個模型犯不同的錯,但是在綜合時能夠取長補短,使得綜合後的模型性能更好。

那麽如何構建不同的基學習器?如何將基學習器綜合起來?

如何構建不同的學習器
1、采用不同的學習算法

2、采用相同的學習算法,但是使用不同的參數
3、采用不同的數據集,其中采用不同的樣本子集,在每個數據集中使用不同的特征

如何綜合不同的基學習器
1、投票法
每個基學習器具有相同的權重
2、有權重的投票
可用不同的方法來確定權重
3、訓練一個新模型來確定如何綜合
stacking
我們一般偏好簡單的模型(線性回歸)

主要的集成學習模式有以下幾種
1、bagging random forest(隨機森林)
2、boosting
adaboost
GBDT
3、stacking

bagging
在集成算法中,bagging 方法會在原始訓練集的隨機子集上構建一類黑盒估計器的多個實例,然後把這些估計器的預測結果結合起來形成最終的預測結果。 該方法通過在構建模型的過程中引入隨機性,來減少基估計器的方差(例如,決策樹)。 在多數情況下,bagging 方法提供了一種非常簡單的方式來對單一模型進行改進,而無需修改背後的算法。 因為 bagging 方法可以減小過擬合,所以通常在強分類器和復雜模型上使用時表現的很好(例如,完全決策樹,fully developed decision trees),相比之下 boosting 方法則在弱模型上表現更好(例如,淺層決策樹,shallow decision trees)。

bagging 方法有很多種,其主要區別在於隨機抽取訓練子集的方法不同:

如果抽取的數據集的隨機子集是樣例的隨機子集,我們叫做 Pasting 。
如果樣例抽取是有放回的,我們稱為 Bagging 。
如果抽取的數據集的隨機子集是特征的隨機子集,我們叫做隨機子空間 (Random Subspaces)。
最後,如果基估計器構建在對於樣本和特征抽取的子集之上時,我們叫做隨機補丁 (Random Patches) 。
在 scikit-learn 中,bagging 方法使用統一的 BaggingClassifier 元估計器(或者 BaggingRegressor ),輸入的參數和隨機子集抽取策略由用戶指定。max_samples 和 max_features 控制著子集的大小(對於樣例和特征), bootstrap 和 bootstrap_features 控制著樣例和特征的抽取是有放回還是無放回的。 當使用樣本子集時,通過設置 oob_score=True ,可以使用袋外(out-of-bag)樣本來評估泛化精度。

采樣概率

在Bagging中,一個樣本可能被多次采樣,也可能一直不被采樣,假設一個樣本一直不出現在采樣集的概率為(1-1/N) ** N,那麽對其求極限可知,原始樣本數據集中約有63.2%的樣本出現在了,Bagging使用的數據集中,同時在采樣中,我們還可以使用袋外樣本(out of Bagging)來對我們模型的泛化精度進行評估.

最終的預測結果

對於分類任務使用簡單投票法,即每個分類器一票進行投票(也可以進行概率平均)
對於回歸任務,則采用簡單平均獲取最終結果,即取所有分類器的平均值

基於KNN的Bagging算法

關於參數和方法要註意的是:

首先控制特征子采樣與樣本子采樣是否采用,采用的話是否要註意控制比例(一般而言,不要采取較小的數值,太小的特征子采樣和樣本子采樣都會造成子學習器的性能太差.一般而言特征選擇越少,方差越大,這點可以與最後的實驗方差偏差分解對比分析).
其次控制Bagging中的隨機數參數random_state固定,不然不同實驗的結果將不一致,同時要註意的很多時候random_state對於測試誤差的影響很大,因此加入你想要在某一個數據集上使用Bagging,那麽建議多嘗試幾個不同的Random_state
oob_score = True 對性能有一定的提升(使用袋外樣本進行泛化能力的評估,但是很多時候效果並不明顯,或者看不出什麽效果)
其他參數一般默認即可

from sklearn.ensemble import BaggingClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score

# load data from sklearn import datasets,model_selection
def load_data():
    iris=datasets.load_iris() # scikit-learn 自帶的 iris 數據集
    X_train=iris.data
    y_train=iris.target
    return model_selection.train_test_split(X_train, y_train,test_size=0.25,random_state=0,stratify=y_train)

bagging = BaggingClassifier(KNeighborsClassifier(),max_samples=0.1,max_features=0.5,random_state=1)

X_train,X_test,y_train,y_test=load_data()

bagging.fit(X_train,y_train)
y_pre = bagging.predict(X_test)
print(accuracy_score(y_test,y_pre))

boosting
Boosting主要是Adaboost(Adaptive Boosting),它與Bagging的不同在於他將權重賦予每個訓練元組,生成基分類器的過程為叠代生成。每當訓練生成一個分類器M(i)時要進行權重更新,使得M(i+1)更關註被M(i)分類錯誤的訓練元組。最終提升整體集合的分類準確率,集成規則是加權投票,每個分類器投票的權重是其準確率的函數。

繼續詳細介紹的話,假設數據集D,共有d類。(X1,Y1)…(Xd,Yd),Yi是Xi的類標號,假設需要生成k的分類器。其步驟為:

1、對每個訓練元組賦予相等的權重1/d。

2、for i=1:k

從D中進行有放回的抽樣,組成大小為d的訓練集Di,同一個元組可以被多次選擇,而每個元組被選中的幾率由權重決定。利用Di訓練得到分類器Mi,然後使用Di作為測試集計算Mi的誤差。然後根據誤差調整權重。

當元組沒有被正確分類時,則權重增加;反之權重減少。然後利用新的權重為下一輪訓練分類器產生訓練樣本。使其更“關註”上一輪中錯分的元組。

3、進行加權投票集成

Bagging與Boosting的差異

通過上述簡單的介紹,可以看出這兩種集成算法主要區別在於“加沒加權”。Bagging的訓練集是隨機生成,分類器相互獨立;而Boosting的分類器是叠代生成,更關註上一輪的錯分元組。因此Bagging的各個預測函數可以並行生成;而Boosting只能順序生成。因此對於像一些比較耗時的分類器訓練算法(如神經網絡等)如果使用Bagging可以極大地解約時間開銷。

但是通過在大多數數據集的實驗,Boosting的準確率多數會高於Bagging,但是也有極個別數據集使用Boosting反倒會退化。

stacking
stakcing常常在各大數據挖掘競賽中被廣泛使用,號稱“大殺器”。是數據挖掘競賽高端玩家必備技能,本篇文章就對stakcing的一些基本原理進行介紹。

首先,在我看來stacking 嚴格來說不能稱為一種算法,我理解的是一種非常精美而復雜的對模型的集成策略。大家都知道,在給定了數據集的情況下,數據內部的空間結構和數據之間的關系是非常復雜的。而不同的模型,其實很重要的一點就是在不同的角度去觀測我們的數據集。比如說,KNN 可能更加關註樣本點之間的距離關系(包括歐幾裏得距離(Euclidean Distance)、明可夫斯基距離(Minkowski Distance 等等),當樣本距離相對較近, KNN 就把他們分為一類;而決策樹,可能更加關註分裂節點時候的不純度變化,有點像我們自己找的規則,在滿足某個條件且滿足某個條件的情況下,決策樹把樣本分為一類等等。也就是說,不同的算法模型,其實是在不同的數據空間角度和數據結構角度來觀測數據,然後再依據它自己的觀測,結合自己的算法原理,來建立一個模型,在新的數據集上再進行預測。這樣大家就會有個疑問了,俗話說:三人行必有我師。既然是不同的算法對數據有不同的觀測,那麽我們能不能相互取長補短,我看看你的觀測角度,你看看我的觀測角度,咱倆結合一下,是不是可以得到一個更加全面更加優秀的結果呢?答案是肯定的。在我當初學基礎算法的時候就有這麽一個疑問,但是不知道怎麽結合,直到有一天看到了 stacking的框架,瞬間感覺找到了一片新天地~~~~下面我從以下幾個方面介紹 stacking。

一、stacking 的框架結構與運行過程:

剛開始看 stacking 好像是交叉檢驗的既視感,其實並不是這樣。假設是五折的stacking,我們有一個train 數據集和一個test 數據集,那麽一個基本的stacking 框架會進行如下幾個操作:

1、選擇基模型。我們可以有 xgboost,lightGMB,RandomForest,SVM,ANN,KNN, LR 等等你能想到的各種基本算法模型。

2、把訓練集分為不交叉的五份。我們標記為 train1 到 train5。

3、從 train1 開始作為預測集,使用 train2 到 train5 建模,然後預測 train1,並保留結果;然後,以 train2 作為預測集,使用 train1,train3 到 train5 建模,預測 train2,並保留結果;如此進行下去,直到把 train1 到 train5 各預測一遍;

4、在上述建立的五個模型過程中,每個模型分別對 test 數據集進行預測,並最終保留這五列結果,然後對這五列取平均,作為第一個基模型對 test 數據的一個 stacking 轉換。

5、把預測的結果按照 train1 到 trian5 的位置對應填補上,得到對 train 整個數據集在第一個基模型的一個 stacking 轉換。

6、選擇第二個基模型,重復以上 2-5 操作,再次得到 train 整個數據集在第二個基模型的一個 stacking 轉換。

7、以此類推。有幾個基模型,就會對整個train 數據集生成幾列新的特征表達。同樣,也會對test 有幾列新的特征表達。

8、一般使用LR 作為第二層的模型進行建模預測。

bagging的優點:
易於並行計算
可以使用不在訓練集中的樣本來估計基學習器的性能
boosting的優點:
學習速度快能夠有效利用弱學習器構建強大的學習器
boosting缺點與bagging相比更激進,更容易受噪聲影響過擬合,不易並行
stacking多用於最終綜合多個性能較好的模型,最易於過擬合

如何避免過擬合:
1、引入隨機性
是機器學習中一個廣為使用的避免過擬合的方法

stacking示例代碼

from sklearn import datasets  

iris = datasets.load_iris()  
X, y = iris.data[:, 1:3], iris.target  

from sklearn import model_selection  
from sklearn.linear_model import LogisticRegression  
from sklearn.neighbors import KNeighborsClassifier  
from sklearn.naive_bayes import GaussianNB   
from sklearn.ensemble import RandomForestClassifier  
from mlxtend.classifier import StackingClassifier  
import numpy as np  

clf1 = KNeighborsClassifier(n_neighbors=1)  
clf2 = RandomForestClassifier(random_state=1)  
clf3 = GaussianNB()  
lr = LogisticRegression()  
sclf = StackingClassifier(classifiers=[clf1, clf2, clf3],   
                          meta_classifier=lr)  

print(‘3-fold cross validation:\n‘)  

for clf, label in zip([clf1, clf2, clf3, sclf],   
                      [‘KNN‘,   
                       ‘Random Forest‘,   
                       ‘Naive Bayes‘,  
                       ‘StackingClassifier‘]):  

    scores = model_selection.cross_val_score(clf, X, y,   
                                              cv=3, scoring=‘accuracy‘)  
    print("Accuracy: %0.2f (+/- %0.2f) [%s]"   
          % (scores.mean(), scores.std(), label))  

常用的集成學習方法