機器學習回顧篇(12):集成學習之Bagging與隨機森林

 

1 引言

集成學習算法是當下煊赫一時的一類算法,在諸多機器學習大賽中都頻繁出現它的身影。準確來講,集成學習算法並非一個單獨的機器學習算法,而是經過構建多個學習器,博採衆家之長,共同求解問題的一種思想。古語有云:「三個臭皮匠頂個諸葛亮」。一個簡單的學習器也許不能很好的擬合數據,可是結合多個不一樣的學習器去解決問題,每每就可能有更加不俗的表現。 本篇博文中,咱們先來詳細說說集成學習思想以及分類,而後對其中的Bagging算法展開介紹。javascript

2 集成學習

引言中說過,所謂集成學習就是先產生一組單個的學習器,咱們姑且將這些單個的學習器稱爲「個體學習器」,而後經過某種策略將這些個體學習器結合起來共同完成學習任務,以下圖所示。那麼,有兩個問題須要解決:第一,若是得到個體學習器;第二,如何將各個體學習器的結果結合到一塊兒。
imagecss

在回答第一個問題前,咱們必須明確,對集成學習中單個學習器必須知足兩個條件:
(1)學習器之間應該有差別性。若是使用的單個學習器將沒有差別,那麼集成起來的結果是沒有變化的。
(2)每一個學習器的精度必須大於0.5。在集成學習中,單個分類器不須要很強,由於越強的分類器訓練過程就越複雜,甚至容易發生過擬合,只須要保證每一個學習器準確率大於0.5,由於若是單個學習的的準確率小於0.5,隨着集成規模的增長,分類精度不斷降低,反之若是精度大於0.5,就算簡單的學習器,經過足夠數量的組合最終精度也會能夠趨向於1。能夠經過下圖來理解這兩個條件。 imagehtml

 

在這兩個條件前提下,對於第一個問題,有兩種解決思路。一種是使用不一樣類別的算法來構建個體學習器,例如對於同一個任務分別使用決策樹算法、支持向量機、神經網絡等不一樣算法來構建學習器。另外一種思路是全部個體學習器都使用同一種算法進行構建,這種思路是目前集成學習算法的主流。在全部個體學習器都使用同種算法構建時,如何保證學習器之間的差別性呢?有兩種方案:html5

  • 每次訓練個體學習器時,對原始數據集進行抽樣得到不一樣數據集做爲當前訓練集,每個訓練樣本在抽樣訓練集中能夠屢次或不出現,通過$T$次訓練後,可獲得$T$個不一樣的沒有相互依賴的個體學習器學習器。Bagging、隨機森林就是這種方案的表明。
  • 經過更新權重的方式不斷地使用一個弱學習器彌補前一個弱學習器的「不足」的過程,來串行地構造一個較強的學習器,這個強學習器可以使目標函數值足夠小。這一方案的表明是Boosting系列的算法,包括Adaboost、GBDT、XGBOOST等

在本文中,咱們先對第一種方案的兩種算法——Bagging和隨機森林進行介紹,在後續的博文中,再對Adaboost、GBDT等算法進行分析。java

3 Bagging

Bagging是並行式集成學習方法的最典型表明,算法名稱來源於Bootstrap aggregating的簡寫,又稱裝袋算法,這種算法直接採用自助採樣法得到$T$個各不相同的數據集,分別使用這$T$個數據集進行訓練可得到$T$個個體學習器,再將這些學習器組合起來共同完成分類或者回歸任務。當完成分類任務時,採用簡單投票法對$T$個體學習器結果進行組合後輸出;當染成迴歸任務時,採用簡單平均法對$T$個個體學習器學習結果進行組合輸出。node

image

3.1 自助採樣法

自助採樣法(Bootstrap sampling是一種從給定原始數據集中有放回的均勻抽樣,也就是說,每當選中一個樣本,它等可能地被再次選中並被再次添加到訓練集中。對於給定包含$m$個樣本的原始數據集$D$,進行自助採樣得到$D'$,具體操做方式:每次採樣時,從幾何$D$中隨機抽取一個樣本拷貝一份到集合$D'$中,而後將樣本放回集合$D$中,是的該羊被後續採樣中仍有可能被採集到;重複這一步驟$m$次後,就能夠得到一樣包含$m$個樣本的集合$D'$,集合$D'$就是自助採樣的最終結果。能夠想象,集合$D$中的樣本有一部分會在集合$D'$中出現重複出現,而有些樣本卻一次都不出現。在$m$次抽樣中,某個樣本從未被抽到的機率爲${(1 - \frac{1}{m})^m}$,當集合$D$樣本足夠多時有: $$\mathop {\lim }\limits_{m \to \infty } {(1 - \frac{1}{m})^m} = \frac{1}{e} \approx 0.368$$ 也就是說,原始集合$D$中有36.8%的樣本不包含在經過自助採樣法得到的集合$D'$中。在Bagging中,未被採集到的36.8%的樣本能夠用做測試集對個體學習器性能進行評估,當個體學習器使用決策樹算法構建時,這部分用本能夠用來輔助樹剪枝;使用神經網絡構建個體學習器時,能夠用來防止過擬合。python

3.2 結合策略

假設共有$T$個個體學習器,以$\{ {h_1},{h_2}, \cdots ,{h_T}\} $表示,其中樣本$x$經$h_i$後的輸出值爲$h_i(x)$。對於結合$T$個個體學習器輸出值,主要有一下幾種策略:jquery

(1)平均法 平均法經常使用於迴歸類任務的數值型輸出,包括簡單平均法、加權平均法等。linux

  • 簡單平均法 $$H(x) = \frac{1}{T}\sum\limits_{i = 1}^T {{h_i}(x)} $$
  • 加權平均法 $$H(x) = \sum\limits_{i = 1}^T {{w_i}{h_i}(x)} $$ 式中,$w_i$是個體學習器$h_i$的權重,一般要求${w_i} \geqslant 0$且$\sum\limits_{i = 1}^T {{w_i}} = 1$。至於$w_i$的具體值,能夠根據$h_i$的具體表現來肯定,$h_i$準確率越高,$w_i$越大。
    對於兩種平均法的選擇上,當個體學習器性能相差較大時,選用加權平均法;當各個體學習器性能相近時,使用簡單加權平均法。

(2)投票法
投票法更多用於做爲分類任務的集成學習的結合策略。android

  • 相對多數投票法 也能夠認爲是多數決策法,即預測結果中票數最高的分類類別。若是不止一個類別得到最高票,則隨機選擇一個做爲最終類別。
  • 絕對多數投票法 不光要求得到票數最高,並且要求票數過半,不然決絕輸出。
  • 加權投票法 與加權平均法相似,每一個個體學習器的分類票數要乘以一個權重,最終將各個類別的加權票數求和,最大的值對應的類別爲最終類別。

(3)學習法
學習法是一種比平均法和投票法更爲強大複雜的結合策略,學習法以全部個體學習器的輸出做爲一個數據集,額外使用一個學習器對該數據及進行學習,而後輸出最終的結果。Stacking方法是學習法的一個經典表明,目前大多數應用中所說的學習法都是指Stacking方法。甚至由於Stacking方法的特殊性和複雜性,不少資料中將Stacking方法當作是與Bagging和Boosting同樣的一類集成學習算法。
Stacking方法中將以前提到的全部個體學習器稱爲初級學習器,將用於結合的學習器稱爲次級學習器。Stacking方法先從原始數據集訓練處初級學習器,而後「生成」一個新的數據集用於訓練次級學習器。在新的數據集中,初級學習器的輸出被當作樣本輸出特徵,而初始樣本的類別標籤人被當作新數據及的類別標籤。(注:關於Stacking能夠參考這篇博客

 

4 隨機森林

4.1 算法介紹

隨機森林(Random Forest,建成RF)也是一種十分流行的算法,原理與Bagging很是類似,甚至有不少資料認爲隨機森林是Bagging的一個分支,一個擴展變體。若是已經理解了Bagging算法,那麼如今再來看隨機森林將再將單不過。
從名稱上能夠推測,隨機森林是以決策樹爲學習算法構建個體學習器並採用Bagging思想集成的一種算法。確實也是如此,但卻不止如此,由於隨機森林在構建決策時,不只在樣本選擇上進行了隨機採樣,同時在特徵屬性的選擇上也進行了隨機選取。在以前介紹決策樹算法的博客中說過,傳統的決策樹算法在選擇最優特徵屬性時老是從當前數據集全部特徵屬性(假設共有$d$個特徵屬性)中選擇一個最優的特徵屬性做爲當前樹節點對數據集進行劃分;但在隨機森林中,使用決策樹算法構建個體學習器時,先從$d$個屬性中隨機選擇$k$個組成新的訓練集,選擇最優分裂屬性時,從這$k$個屬性中進行擇優選取。這就是隨機森林中構建決策樹與傳統決策樹的不一樣。

須要注意,有兩個因素對隨機森林性能影響很大:

  • 森林中任意兩棵樹的相關性:相關性越大,錯誤率越大;
  • 森林中每棵樹的分類能力:每棵樹的分類能力越強,整個森林的錯誤率越低

$k$控制了選擇特徵訓練集的隨機程度,不管是相關性仍是分類能力,都與$k$值選取息息相關,減少特徵選擇個數$k$,樹的相關性和分類能力也會相應的下降;增大$k$,二者也會隨之增大。因此關鍵問題是如何選擇最優的m(或者是範圍),這也是隨機森林惟一的一個參數。當$k=d$時,與傳統的決策樹算法就沒有什麼區別了,都是從原始完整的訓練集中進行選擇,當$k=1$時,則是隨機選擇一個特徵屬性進行訓練;通常狀況下,推薦$k = {\log _2}d$。

隨機森林不只在每一個個體學習器訓練樣本選擇上,延用了Bagging算法中的自助採樣法,保證了每一個個體學習器訓練集的差別性,同時也經過特徵屬性的選擇,進一步進行擾動,保證了個體信息器的多樣性,這也是隨機森林在衆多集成算法中表現突出的緣由。 最後總結一下隨機森林的優缺點:

優勢:
(1) 每棵樹都選擇部分樣本及部分特徵,必定程度避免過擬合;
(2) 每棵樹隨機選擇樣本並隨機選擇特徵,使得具備很好的抗噪能力,性能穩定;
(3) 能處理很高維度的數據,而且不用作特徵選擇;
(4) 適合並行計算;
(5) 實現比較簡單;
缺點:
(1)當隨機森林中的決策樹個數不少時,訓練時須要的空間和時間會較大;
(2)隨機森林模型還有許多很差解釋的地方,有點算個黑盒模型。

4.2 代碼實現

爲了方便展現,仍是使用自定義的二維數據集:

In [43]:
import numpy as np
import matplotlib.pyplot as plt 
import copy
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D


a = np.random.normal(20,5,300)
b = np.random.normal(15,5,300)
c = np.random.normal(20,5,300)
cluster1 = np.array([[x, y, z, 1] for x, y, z in zip(a,b, c)])

a = np.random.normal(20,5,300)
b = np.random.normal(45,5,300)
c = np.random.normal(45,5,300)
cluster2 = np.array([[x, y, z, 2] for x, y, z in zip(a,b,c)])

a = np.random.normal(55,5,300)
b = np.random.normal(30,5,300)
c = np.random.normal(45,5,300)
cluster3 = np.array([[x, y, z, 3] for x, y, z in zip(a,b,c)])

dataset = np.append(np.append(cluster1,cluster2, axis=0),cluster3, axis=0)
In [44]:
from sklearn.model_selection import train_test_split
from sklearn.utils import shuffle
x_train,x_test,y_train,y_test = train_test_split(dataset[:,:3],dataset[:,-1],test_size=0.3,random_state=0)  # 將數據劃分爲訓練集,測試集
x_train,y_train = shuffle(x_train,y_train)  # 隨機打亂數據
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.set_zlabel('Z')  # 座標軸
ax.set_ylabel('Y')
ax.set_xlabel('X')
ax.scatter(x_train[:,0], x_train[:,1], x_train[:,2])
plt.show()
 
In [45]:
from sklearn.ensemble import RandomForestClassifier   # 導入隨機森林
clf = RandomForestClassifier()
clf.fit(x_train, y_train)
 
/home/chb/anaconda3/envs/study_python/lib/python3.7/site-packages/sklearn/ensemble/forest.py:245: FutureWarning: The default value of n_estimators will change from 10 in version 0.20 to 100 in 0.22.
  "10 in version 0.20 to 100 in 0.22.", FutureWarning)
Out[45]:
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
                       max_depth=None, max_features='auto', max_leaf_nodes=None,
                       min_impurity_decrease=0.0, min_impurity_split=None,
                       min_samples_leaf=1, min_samples_split=2,
                       min_weight_fraction_leaf=0.0, n_estimators=10,
                       n_jobs=None, oob_score=False, random_state=None,
                       verbose=0, warm_start=False)
In [46]:
dataset[0]
Out[46]:
array([31.35045639, 14.1587136 , 11.3989477 ,  1.        ])
In [47]:
clf.predict([[22.63809831, 24.57126294, 18.54161034]])  # 對當個樣本類別進行預測
Out[47]:
array([1.])
In [49]:
# 驗證準確率
from sklearn.metrics import accuracy_score
print('模型準確率爲:',accuracy_score(y_test, clf.predict(x_test)))
 
模型準確率爲: 1.0
In [50]:
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
for x, y, z, p in zip(x_test[:,0], x_test[:,1], x_test[:,2], y_test):
    if int(p)==1:
        ax.scatter(x, y, z, c='r')
    elif int(p)==2:
        ax.scatter(x, y, z, c='y')
    else:
        ax.scatter(x, y, z, c='g')
ax.set_zlabel('Z')  # 座標軸
ax.set_ylabel('Y')
ax.set_xlabel('X')
plt.show()
 
相關文章
相關標籤/搜索