集成學習與隨機森林(一)投票分類器


集成學習與隨機森林

假設我們現在提出了一個復雜的問題,並拋給幾千個隨機的人,然后匯總他們的回答。在很多情況下,我們可以看到這種匯總后的答案會比一個專家的答案要更好。這個稱為“群眾的智慧”。同理,如果我們匯總一組的預測器(例如分類器與回歸器)的預測結果,我們可以經常獲取到比最優的單個預測器要更好的預測結果。這一組預測器稱為一個集成,所以這種技術稱為集成學習,一個集成學習算法稱為一個集成方法。

舉一個集成方法的例子,我們可以訓練一組決策樹分類器,每個都在訓練集的一組不同的隨機子集上進行訓練。在做決策時,我們可以獲取所有單個決策樹的預測結果,然后根據各個結果對每個類別的投票數,最多票的類別獲勝。這種集成決策樹稱為隨機森林。盡管它非常簡單,不過它是當前最強大的機器學習算法之一。

我們之前在機器學習項目流程里介紹過,我們一般會在接近項目末尾的時候使用集成方法。在我們已經有了幾個非常好的預測器之后,要嘗試將它們組合,可能會形成一個更好的預測器。實際上,在機器學習比賽中,獲勝的解決方案一般都引入了好幾個集成方法。

在這章我們會討論幾個最流行的集成方法,包括bagging,boosting,以及stacking。同時我們也會介紹隨機森林。

 

投票分類器

假設我們訓練了幾個分類器,每個都能達到80%以上的准確率。假設這些分類器可能是邏輯回歸分類器、SVM分類器、隨機森林分類器、以及KNN分類器等等,如下圖所示:

 

一個非常簡單,但是能創建一個更好的分類器的辦法是:聚合每個分類器預測的類別,然后選其中投票最多的類別。如下圖所示,這種多數投票分類器稱為一個硬投票(hard voting)分類器。

 

令人出乎意料的是,這種投票分類器經常可以比單個最優分類器的准確度要更高。而且,即使每個分類器都是一個弱學習者(weak learner,也就是說它的預測能力僅比隨機猜稍微高一點),集成的結果仍可以是一個強學習者(strong learner,能達到高准確率)。

這個是怎么可能呢?下面我們用一個類比來幫助解釋一些原理。假設我們有一個稍微不太公平的硬幣,它有51%的幾率面朝上,49%的幾率面朝下。如果我們拋1000次,我們一般或多或少會得到510次面朝上,490次面朝下,所以“面朝上更多“。如果我們使用數學計算,就會發現,對於“面朝上更多”這個事件,在拋了1000次硬幣后,它的概率接近於75%。我們拋的次數越多,這個幾率越高(例如,拋10000次,“面朝上更多”這個事件的概率可達97%)。這個可由大數定律解釋:只要我們保持拋硬幣,面朝上的概率會愈接近它的自然概率(51%)。下圖展示的是10組拋硬幣(此硬幣為前面提到的不公平硬幣)的結果。我們可以看到,在拋硬幣的次數增加后,面朝上的概率接近51%。最終10組都會接近51%的面朝上結果:

 

類似,假設我們構造了一個集成,包含1000個分類器,這些分類器每個單獨的正確率僅有51%。如果我們使用投票最多的類別作為預測結果,我們可能能獲取75%的准確率。這就好比1000個分類器中,“面朝上更多“的概率。不過這個成立的條件在於:所有的分類器都是完全獨立的,它們產生的錯誤也都是不相關的。這種情況很明顯在機器學習中不是這么回事,因為它們都是在同一個數據集上進行的訓練。它們更有可能產生同樣類型的錯誤,所以也會有很多票投給錯誤的類別,並最終降低了集成的准確率。

集成學習在預測器互相之間(盡可能地)獨立時表現最好。其中一個辦法就是使用完全不同的算法訓練不同的分類器。這個可以增加它們產生不同類型錯誤的幾率,提升集成的准確度。

下面的代碼創建並訓練一個投票分類器,由3個不同的分類器組成:

from sklearn.model_selection import train_test_split
from sklearn.datasets import make_moons
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import VotingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC

# compose moon data
X, y = make_moons(n_samples=500, noise=0.30, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)

log_clf = LogisticRegression()
rnd_clf = RandomForestClassifier()
svm_clf = SVC()

voting_clf = VotingClassifier(
    estimators=[('lr', log_clf), ('rf', rnd_clf), ('svc', svm_clf)],
    voting='hard'
)

voting_clf.fit(X_train, y_train)

 

我們看一下每個分類器在測試集上的准確率:

from sklearn.metrics import accuracy_score

for clf in (log_clf, rnd_clf, svm_clf, voting_clf):
    clf.fit(X_train, y_train)
    y_pred = clf.predict(X_test)
print(clf.__class__.__name__, accuracy_score(y_test, y_pred))
>LogisticRegression 0.864
 RandomForestClassifier 0.888
 SVC 0.888
 VotingClassifier 0.896

 

可以看到投票分類器性能比單個分類器有稍微一點點提升。

如果所有的分類器都能估計每個類別的概率(例如,它們都有一個predict_proba()方法),我們就可以告訴sk-learn使用軟投票(soft voting)。軟預測會先獲取所有各個分類器對某條數據的預測類別概率,然后計算各個類別概率的平均值,取其中最高的類別概率作為輸出的類別。一般軟投票會比硬投票的性能更好,因為它會給與那些高度自信的投票更多的權重。在使用時僅需要將voting=”hard” 改為 voting=“soft”即可,同時還要確保所有的分類器都能預測類別的概率。默認情況下SVC是不支持預測類別的概率的,所以我們需要將它的probability超參數設置為True(這樣會讓SVC類使用交叉驗證來估計類別的概率,但是訓練速度會下降,並且它會增加一個predict_proba() 方法)。如果我們修改前面的方法,指定投票為軟投票(soft voting):

svm_clf = SVC(probability=True)
voting_clf = VotingClassifier(
    estimators=[('lr', log_clf), ('rf', rnd_clf), ('svc', svm_clf)],
    voting='soft'
)

for clf in (log_clf, rnd_clf, svm_clf, voting_clf):
    clf.fit(X_train, y_train)
    y_pred = clf.predict(X_test)
    print(clf.__class__.__name__, accuracy_score(y_test, y_pred))
>LogisticRegression 0.864
 RandomForestClassifier 0.88
 SVC 0.888
 VotingClassifier 0.912

可以看到准確率提升到了91.2%。

以上便是投票分類器,接下來我們會繼續介紹投票分類器里的兩種方法:Bagging與 Pasting。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM