30分鐘學會如何使用集成學習(什麼是集成學習)

首先我們建造如下數據集,作爲接下來的訓練數據

  • 二維數據集
  • 500個樣本,2個特徵(0, 1)
import numpy as np
import matplotlib.pyplot as plt
## 創建數據集
from sklearn import datasets

x, y = datasets.make_moons(n_samples=500, noise=0.3, random_state=42)
plt.scatter(x[y==0,0],x[y==0,1])
plt.scatter(x[y==1,0],x[y==1,1])
plt.show()

在這裏插入圖片描述

一,什麼是集成學習

集成學習的思想其實就是我們使用多個弱學習器一起解決一個問題,類似於“三個臭皮匠賽過諸葛亮”的道理。

首先,我們把數據集分爲訓練集和測試集

## 進行數據切分
from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=42)

我們分別使用邏輯迴歸SVC決策樹進行數據學習,並且分別得到他們每一個準確率。

from sklearn.linear_model import LogisticRegression

log_clf = LogisticRegression()
log_clf.fit(x_train, y_train)
log_clf.score(x_test, y_test)
>>>0.864
from sklearn.svm import SVC

svm_clf = SVC()
svm_clf.fit(x_train, y_train)
svm_clf.score(x_test, y_test)
>>>0.888
from sklearn.tree import DecisionTreeClassifier

df_clf = DecisionTreeClassifier()
df_clf.fit(x_train, y_train)
df_clf.score(x_test, y_test)
>>>0.84

接下來,再分別適用三個基學習器對測試集進行預測

## 分別得到三種基學習器的預測結果
y_predict1 = log_clf.predict(x_test)
y_predict2 = svm_clf.predict(x_test)
y_predict3 = df_clf.predict(x_test)

最後,我們通過投票的方式集成以上三種基學習器的學習結果

## 集成以上三種的預測數據,通過投票的方法得到集成結果
y_predict = np.array((y_predict1 + y_predict2 + y_predict3) >= 2,dtype=int)
y_predict[:10]
>>>array([1, 0, 0, 1, 1, 1, 0, 0, 0, 0])

通過計算集成學習的準確率可以看出,準確率有明顯的提升,而這僅僅使用了500個樣本和3個基學習器。

## 計算集成學習的準確率
from sklearn.metrics import accuracy_score

accuracy_score(y_test, y_predict)
>>>0.896

二,使用SKlearn中提供的集成學習器解決分類問題

2.1 Voting Classifier 投票集成

我們可以指定想用那幾個基學習器,例如下面我們就指定選用了邏輯迴歸SVC決策樹作爲基學習器。

2.1.1 少數服從多數原則的投票集成-Hard Voting

這裏我們依舊使用邏輯迴歸SVC決策樹作爲基學習器。
參數說明:

  • 使用哪幾個基學習器 estimators = [ (‘名字1’, 基學習器1), (‘名字2’, 基學習器2)…]
  • voting=‘hard’ 表示使用簡單地投票方法得到集成結果(少數服從多數原則,後邊會提到考慮概率的投票方法)
from sklearn.ensemble import VotingClassifier

## 考慮我們要使用那些基學習器進行集成
estimators = [
    ('log_clf', LogisticRegression()),
    ('svm_clf', SVC()),
    ('df_clf', DecisionTreeClassifier())
]

## 訓練集成算法(voting='hard'表示使用投票方式得到集成結果)
voting_clf = VotingClassifier(estimators=estimators, voting='hard')
voting_clf.fit(x_train, y_train)

這裏我把訓練後返回的學習器參數單獨列了出來(如下),可以看到我們使用的每一個基學習器的參數。

>>>VotingClassifier(estimators=[('log_clf',
                              LogisticRegression(C=1.0, class_weight=None,
                                                 dual=False, fit_intercept=True,
                                                 intercept_scaling=1,
                                                 l1_ratio=None, max_iter=100,
                                                 multi_class='warn',
                                                 n_jobs=None, penalty='l2',
                                                 random_state=None,
                                                 solver='warn', tol=0.0001,
                                                 verbose=0, warm_start=False)),
                             ('svm_clf',
                              SVC(C=1.0, cache_size=200, class_weight=None,
                                  coef0=0.0, decision_f...
                             ('df_clf',
                              DecisionTreeClassifier(class_weight=None,
                                                     criterion='gini',
                                                     max_depth=None,
                                                     max_features=None,
                                                     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,
                                                     presort=False,
                                                     random_state=None,
                                                     splitter='best'))],
                 flatten_transform=True, n_jobs=None, voting='hard',
                 weights=None)

依然和之前學過的學習器一樣,通過score方法得到學習器的準確率

voting_clf.score(x_test, y_test)
>>>0.904

2.1.2 考慮概率的投票集成-Soft Voting

假設有以下5種基學習器

  • 模型1 A-99%;B-1% ---- 最終結果:A
  • 模型2 A-49%;B-51% ---- 最終結果:B
  • 模型3 A-40%;B-60% ---- 最終結果:B
  • 模型4 A-90%;B-10% ---- 最終結果:A
  • 模型5 A-30%;B-70% ---- 最終結果:B

若按照簡單投票的方法的到最終結果,則結果爲B

但這樣顯然是不合理的,因爲很容易看出來選擇A的基學習器更加確定自己的選擇,而B則不是。

所以我們考慮對每一個選則進行加權(選擇的確定性)

  • A-(0.99 + 0.49 + 0.4 + 0.9 + 0.3)/5 = 0.616
  • B-(0.01 + 0.51 + 0.6 + 0.1 + 0.7)/5 = 0.384

則此時最終結果爲A

所以說,我們如果要使用Soft Voting:要求集合的每一個模型都能估計概率。

  • 邏輯迴歸 - 本身就是基於概率模型
  • kNN - 考慮5個最近點,3個是A ,2個是B,則結果爲A-3/5%
  • 決策樹 - 與kNN相似
  • SVC - 要設置參數 probability=True

參數:voting='soft'表示使用考慮概率投票的方法得到集成結果

## 注意:svc算法要設置參數纔會計算概率
estimators = [
    ('log_clf', LogisticRegression()),
    ('svm_clf', SVC(probability=True)),
    ('df_clf', DecisionTreeClassifier())
]

## 設置參數 voting='soft',才支持計算概率
voting_clf2 = VotingClassifier(estimators=estimators, voting='soft')
voting_clf2.fit(x_train, y_train)
>>>VotingClassifier(estimators=[('log_clf',
                              LogisticRegression(C=1.0, class_weight=None,
                                                 dual=False, fit_intercept=True,
                                                 intercept_scaling=1,
                                                 l1_ratio=None, max_iter=100,
                                                 multi_class='warn',
                                                 n_jobs=None, penalty='l2',
                                                 random_state=None,
                                                 solver='warn', tol=0.0001,
                                                 verbose=0, warm_start=False)),
                             ('svm_clf',
                              SVC(C=1.0, cache_size=200, class_weight=None,
                                  coef0=0.0, decision_f...
                             ('df_clf',
                              DecisionTreeClassifier(class_weight=None,
                                                     criterion='gini',
                                                     max_depth=None,
                                                     max_features=None,
                                                     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,
                                                     presort=False,
                                                     random_state=None,
                                                     splitter='best'))],
                 flatten_transform=True, n_jobs=None, voting='soft',
                 weights=None)

通過計算準確率,可以看出對於此數據,通過考慮概率投票得到的集成結果準確率更高。

## 可以看出考慮概率的準確率更高
voting_clf2.score(x_test, y_test)
>>>0.912

2.2 Bagging 和 Pasting

雖然有很多機器學習方法,但從投票角度看,仍然不夠多的;

我們需要創建更多的子模型!集成更多子模型的意見,但是子模型之間不能一致,子模型之間要有差異性

如何創建差異性?

  • 每個子模型只看樣本數據的一部分。
  • 此時,子模型的準確率會降低,但是對於每個子模型不需要太高的準確率。

下邊舉了個例子可以看一下
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
如何從所有數據中取樣

  • 放回取樣 - Bagging(更常用,使用的數據更少,減少了隨機問題的影響)
    統計學中,放回取樣叫 bootstrap
  • 不放回取樣 - Pasting

2.2.1 如何使用 Bagging(套袋分類器)

關於BaggingClassifier]的參數,屬性和方法詳細說明:

這裏我們使用決策樹模型舉例(決策樹模型個容易產生差異性,則當需要很多基學習器時,優先選擇決策樹模型)

from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import BaggingClassifier

# 參數:基學習器 DecisionTreeClassifier(), 
# 構建基學習器數量 n_estimators=500, 
# 每個基學習器訓練所需的樣本數量 max_samples==100, 
# 是否爲放回取樣bootstrap=True
bagging_clf = BaggingClassifier(DecisionTreeClassifier(), 
	n_estimators=500, max_samples=100, bootstrap=True)
bagging_clf.fit(x_train, y_train)
bagging_clf.score(x_test, y_test)
# 如果使用一個決策樹,即是使用所有樣本訓練也會比這個準確度低
>>>0.904

如果創建更多的基學習器呢?

# 創建更多的基學習器(5000個)
bagging_clf2 = BaggingClassifier(DecisionTreeClassifier(), n_estimators=5000, max_samples=100, bootstrap=True)
bagging_clf2.fit(x_train, y_train)
bagging_clf2.score(x_test, y_test)
>>>0.912

2.2.2 關於袋外數據(oob)

沒有選到的數據(稱爲:袋外數據 Out-of-Bag)

放回取樣會導致一部分樣本很有可能沒有取到,平均大約有37%的樣本沒有取到。
因此,我們可以不使用測試數據集,而使用沒有取到的樣本進行測試/驗證。

這時需要在訓練時要設置參數oob_score=True,並且在訓練集成學習器時我們就可以將全部數據都作爲訓練數據。

使用用oob_score_屬性調用得到使用袋外數據測試出的精確度。

我們使用全部數據重新訓練一個集成學習器

  • 基學習器依舊爲決策樹
  • 需要設置參數oob_score=True,其他參數不變
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import BaggingClassifier

bagging_clf3 = BaggingClassifier(DecisionTreeClassifier(), 
	n_estimators=500, max_samples=100, bootstrap=True, oob_score=True)
bagging_clf3.fit(x, y)
>>>BaggingClassifier(base_estimator=DecisionTreeClassifier(class_weight=None,
                                                        criterion='gini',
                                                        max_depth=None,
                                                        max_features=None,
                                                        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,
                                                        presort=False,
                                                        random_state=None,
                                                        splitter='best'),
                  bootstrap=True, bootstrap_features=False, max_features=1.0,
                  max_samples=100, n_estimators=500, n_jobs=None,
                  oob_score=True, random_state=None, verbose=0,
                  warm_start=False)

獲得使用袋外數據測得的準確率

bagging_clf3.oob_score_
>>>0.92

2.2.3 同時對特徵進行隨機採樣

我們可以把樣本看成一個矩陣,橫向代表一個樣本,縱向代表每一種特徵,就相當於隨機取矩陣中的元素(例如下圖,紅色爲隨即取出的樣本數據)
在這裏插入圖片描述
參數說明:

  • 是否針對特徵隨機取樣 bootstrap_features=True
  • 每次特徵取樣的特徵數 max_features=1
random_patches_clf = BaggingClassifier(DecisionTreeClassifier(), 
	n_estimators=100, max_samples=500, bootstrap=True, 
	oob_score=True, bootstrap_features=True, max_features=1)
random_patches_clf.fit(x, y)
random_patches_clf.oob_score_
>>>0.81

可以看出準確率並沒有明顯的提升,這是因爲,我們的樣本數據只有兩個特徵,當我們的數據特徵很多事,才適合對特徵進行隨機取樣。

另外,如果我們設置參數max_samples=樣本總數(相當於每個基學習器都使用了全部的數據),就實現了只針對特進行隨機取樣。

2.3 隨機森林

在Bagging中,如果我們使用的基學習器是決策樹的話,也可以稱爲隨機森林(當然sklearn中也有專門用於決策樹的類)。
決策樹在節點劃分上,在隨機的特徵子集上尋找最優劃分特徵(進一步增加了隨機性)。

2.3.1 RandomForestClassifier

官網參數說明:隨機森林分類器

from sklearn.ensemble import RandomForestClassifier

rf_clf = RandomForestClassifier(n_estimators=500, oob_score=True)
rf_clf.fit(x, y)

可以看出返回的參數,大部分都是決策樹中的所包含的參數。

>>>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=500,
                       n_jobs=None, oob_score=True, random_state=666, verbose=0,
                       warm_start=False)
rf_clf.oob_score_
>>>0.896

2.3.2 ExtraTreesClassifier

官網參數說明:額外的樹分類器

  • 此類實現一個元估計量,該量量估計量適合數據集的各個子樣本上的許多隨機決策樹(又名額外樹),並使用平均數來提高預測準確性和控制過度擬合。

決策樹在節點劃分上,使用隨機的特徵和隨機的閾(yǜ)值
提供額外的隨機性,抑制過擬合,但增大了bias(偏差)
更快的訓練速度

from sklearn.ensemble import ExtraTreesClassifier

et_clf = ExtraTreesClassifier(n_estimators=500, bootstrap=True, oob_score=True)
et_clf.fit(x, y)
>>>ExtraTreesClassifier(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=500,
                     n_jobs=None, oob_score=True, random_state=None, verbose=0,
                     warm_start=False)
et_clf.oob_score_
>>>0.892

三,集成學習解決迴歸問題

上邊講到的都是針對迴歸問題,那麼我們如何讓解決迴歸問題呢?

當然,sklearn也提供了相應的包供我們使用,並且參數與分類問題的集成學習器參數相似,用法也近乎已知,下邊給出了對應的包,具體參數大家可以在官方網站中查詢,這裏就不做過多解釋了。

# 套袋分類器
from sklearn.ensemble import BaggingRegressor
# 隨機森林
from sklearn.ensemble import RandomForestRegressor
# 額外的隨機森林
from sklearn.ensemble import ExtraTreesRegressor

四,Stacking

參考視頻:Stacking【小白勿入系列】
官網說明:

我們回顧一下Voting的集成學習方法
假設我們有3個基學習器:

  1. 分別訓練每一個基學習器
  2. 對於測試數據分別用3個基學習器進行預測
  3. 整合每個基學習器的預測結果
    – 對於分類問題:通過投票方法得到集成學習結果
    – 對於迴歸問題:可以通過計算平均值來得到最終的集成結果
    在這裏插入圖片描述

那麼什麼是Stacking集成學習,就是在上述的步驟中再加一步:

  • 額外添加一層算法(Blending);
  • 我們將基學習器得到的結果作爲輸入,使用上述算法進行二次預測得到最終結果。
    在這裏插入圖片描述
    如何訓練 Stacking學習器:
  1. 首先把訓練數據集合分成兩份;
  2. 其中一份用於訓練每一個基學習器,而另一份則用於訓練添加的那一層算法(Blending)
  3. 最終得到Stacking集成學習器

在這裏插入圖片描述
理解了Stacking的原理我們就可以創建出更加複雜的Stacking學習器
如下圖,我們在原有的基礎上再增加一層基學習器
(則我們需要將數據集分成三份,分別訓練每一層的學習器)在這裏插入圖片描述
所以說,在Stacking中,有幾層和每層有幾個學習器都是超參數,因爲這種複雜性,也導致了比較容易過擬合。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章