集成學習系列第三篇(Boosting相關方法),傳送前兩篇:
文章目錄
一、Boosting
Boosting算法中,個體學習器之間存在強依賴關係。在boosting系列算法中, 典型的算法有 Adaboost、GBDT。
工作機制如下:
- 先從初始訓練集中學習一個基學習器;
- 根據弱學習器的學習錯誤率對訓練樣本分佈進行調整,使得先前基學習器做錯的訓練樣本在後續收到更多關注;
- 基於調整權重後的訓練樣本分佈來訓練下一個弱學習器;
- 如此反覆,直到弱學習器數目達到 T,最終將這 T 個弱學習器進行加權結合。
關鍵問題:
- 如何計算學習誤差率e?
- 如何得到弱學習器權重係數α?
- 如何更新樣本權重D?
- 使用何種結合策略?
二、Adaboost原理
核心思想:針對同一個訓練集訓練不同的分類器(弱分類器),然後把這些弱分類器集合起來,構成一個更強的最終分類器(強分類器)。
其算法本身是通過改變數據分佈來實現的,它根據每次訓練集之中每個樣本的分類是否正確,以及上次的總體分類的準確率,來確定每個樣本的權值。將修改過權值的新數據集送給下層分類器進行訓練,最後將每次訓練得到的分類器最後融合起來,作爲最後的決策分類器。
優點
- Adaboost作爲分類器時,分類精度很高
- 在Adaboost的框架下,可以使用各種迴歸分類模型來構建弱學習器,非常靈活。
- 作爲簡單的二元分類器時,構造簡單,結果可理解。
- 不容易發生過擬合
缺點
- 對異常樣本敏感,異常樣本在迭代中可能會獲得較高的權重,影響最終的強學習器的預測準確性。
1、基本思路
假設我們的訓練集樣本是
訓練集的在第 個弱學習器的輸出權重爲
(1)Adaboost分類
分類問題的誤差率
由於多元分類是二元分類的推廣,這裏假設我們是二元分類問題,輸出爲,則第 個弱分類器 在訓練集上的加權誤差率爲
弱學習器權重係數
對於二元分類問題,第 個弱分類器 的權重係數爲
==》如果分類誤差率 越大,則對應的弱分類器權重係數 越小。也就是說,誤差率小的弱分類器權重係數越大。
==》公式的由來在損失函數優化時介紹。
更新樣本權重D
假設第 個弱分類器的樣本集權重係數爲 ,則對應的第 個弱分類器的樣本集權重係數爲
其中, 是規範因子,
==》從 計算公式可以看出,如果第 個樣本分類錯誤,則 ,導致樣本的權重在第 個弱分類器中增大,如果分類正確,則權重在第 個弱分類器中減少。
==》公式的由來在損失函數優化時介紹。
集合策略
Adaboost分類採用的是加權表決法,最終的強分類器爲
(2)Adaboost迴歸
由於Adaboost的迴歸問題有很多變種,這裏我們以Adaboost R2算法爲準。
迴歸問題的誤差率
對於第 個弱學習器,計算他在訓練集上的最大誤差
計算每個樣本的相對誤差
注意:這裏是誤差爲線性時的情況;若使用平方誤差,則;若使用指數誤差,則
最終得到第 個弱分類器的錯誤率:
弱學習器權重係數
第 個弱分類器 的權重係數爲
更新樣本權重D
第 個弱學習器的樣本集權重係數爲
其中, 是規範因子,
結合策略
採用的是對加權的弱學習器取權重中位數對應的弱學習器作爲強學習器的方法,最終的強迴歸器爲
其中,是所有 , 的中位數值對應序號 對應的弱學習器。
2、AdaBoost分類問題的損失函數優化
Adaboost 是模型爲加法模型,學習算法爲前向分步學習算法,損失函數爲指數函數的分類問題。
-
加法模型:最終的強分類器是若干個弱分類器加權平均而得到的。
-
前向分步學習算法:通過一輪輪的弱學習器學習,利用前一個弱學習器的結果來更新後一個弱學習器的訓練集權重。第 輪的強學習器爲
而第 輪的強學習器爲
則可以得到
-
損失函數爲指數函數,即定義損失函數爲
利用前向分步學習算法的關係可以得到損失函數爲
令 ,它的值不依賴於 ,因此與最小化無關,僅僅依賴於,隨着每一輪迭代而改變。
將這個式子帶入損失函數,損失函數轉化爲
- 損失函數求解過程
- 求 。對任意 ,使上式最小的 由下式得到:
- 將 帶入損失函數,並對 求導,使其等於0,則可以得到
其中, 爲分類錯誤率。
- 樣本權重的更新。
利用 和 ,即可得:
3、AdaBoost二元分類問題算法流程
輸入:樣本集 ,輸出爲 ,弱分類器算法,弱分類器迭代次數 。
輸出:最終的強分類器
(1) 初始化樣本集權重爲
(2) 對於 :
a) 使用具有權重 的樣本集來訓練數據,得到弱分類器
b) 計算 的分類錯誤率
c) 計算弱分類的係數
d) 更新樣本集的權重分佈
其中, 是規範因子,
(3) 構建最終分類器爲:
對於Adaboost多元分類算法,其實原理和二元分類類似,最主要區別在弱分類器的係數上。比如 Adaboost SAMME 算法,它的弱分類器的係數:
其中 爲類別數。從上式可以看出,如果是二元分類,,則上式和我們的二元分類算法中的弱分類器的係數一致。
4、Adaboost迴歸問題的算法流程
爲Adaboost R2迴歸算法過程。
輸入:樣本集 ,弱分類器算法,弱分類器迭代次數 。
輸出:最終的強分類器
(1) 初始化樣本集權重爲
(2) 對於 :
a) 使用具有權重 的樣本集來訓練數據,得到弱分類器
b) 計算訓練集上的最大誤差
c) 計算每個樣本的相對誤差
如果是線性誤差,則
如果是平方誤差,則
如果是指數誤差,則
d) 計算迴歸誤差率
e) 計算弱學習器的係數
f) 更新樣本集的權重分佈爲
其中, 是規範因子,
(3) 構建最終強學習器爲:
其中,是所有 , 的中位數值對應序號 對應的弱學習器。
5、Adaboost算法的正則化
爲了防止Adaboost過擬合,我們通常也會加入正則化項,這個正則化項我們通常稱爲步長(learning rate)。定義爲 ,對於前面的弱學習器的迭代
如果我們加上了正則化項,則有
其中,。對於同樣的訓練集學習效果,較小的 意味着我們需要更多的弱學習器的迭代次數。通常我們用步長和迭代最大次數一起來決定算法的擬合效果。
三、Adaboost實現
1、Adaboost類庫簡介
scikit-learn中Adaboost類庫:
- AdaBoostClassifier——分類
- 兩種實現方法:SAMME和SAMME.R
- AdaBoostRegressor——迴歸
+實現方法: Adaboost.R2(詳見2.1.2)
Adaboost調參
- Adaboost的框架參數
- 弱分類器的參數
2、AdaBoost框架參數
AdaBoostClassifier和AdaBoostRegressor的大部分框架參數相同,下面我們一起討論這些參數,兩個類如果有不同點我們會指出。
(1) base_estimator
:弱分類學習器或者弱迴歸學習器。
- 一般是CART決策樹或者神經網絡MLP,默認是決策樹(
DecisionTreeClassifier
orDecisionTreeRegressor
)。 - 注意:分類中參數
algorithm
選擇的是SAMME.R
,則弱分類學習器還需要支持概率預測(支持predict_proba
方法)
(2) n_estimators
:弱學習器的最大迭代次數,或者說最大的弱學習器的個數。
- 值太小,易欠擬合,值太大,易過擬合,一般選擇一個適中的數值。默認是50。
- 在實際調參的過程中,我們常常將n_estimators和參數learning_rate一起考慮。
(3) learning_rate
:每個弱學習器的權重縮減係數
- 爲了防止Adaboost過擬合,我們通常也會加入正則化項,這個正則化項我們通常稱爲
步長(learning rate)
。 - 定義爲 ,對於前面的弱學習器的迭代 加上了正則化項,則有 , 的取值範圍爲 。
- 對於同樣的訓練集學習效果,較小的 意味着我們需要更多的弱學習器的迭代次數。通常我們用步長和迭代最大次數一起來決定算法的擬合效果,所以
n_estimators
和learning_rate
要一起調參。
(4) algorithm
(只有AdaBoostClassifier有該參數)
- 實現分類Adaboost的兩種算法
SAMME
和SAMME.R
。 - 兩者主要區別:基學習器權重的度量。
SAMME
使用對樣本集分類效果作爲弱學習器權重 (原理中即爲SAMME),而SAMME.R
使用對樣本集分類的預測概率大小來作爲弱學習器權重。 - 默認爲
SAMME.R
,它迭代一般比SAMME
快。但若用SAMME.R
, 則基學習器參數base_estimator
必須使用支持概率預測的分類器。
(5) loss
(只有AdaBoostRegressor有該參數)
Adaboost.R2
算法需要用到——有線性linear
, 平方square
和指數exponential
三種選擇, 默認是線性。
3、弱分類器參數
本部分關注AdaBoostClassifier和AdaBoostRegressor弱學習器參數,僅討論默認的決策樹弱學習器的參數。即CART分類樹DecisionTreeClassifier
和CART迴歸樹DecisionTreeRegressor
的關鍵參數。
(1) max_features
:劃分時考慮的最大特徵數
- 可以使用很多種類型的值:
- 默認是
None
,表示劃分時考慮所有的特徵數; - 如果是
log2
意味着劃分時最多考慮 個特徵; - 如果是
sqrt
或者auto
意味着劃分時最多考慮 個特徵。 - 如果是
整數
,代表考慮的特徵絕對數。 - 如果是
浮點數
,代表考慮特徵百分比,即考慮 取整後的特徵數。其中N爲樣本總特徵數。
- 默認是
- 一般來說,如果樣本特徵數不多,比如小於50,默認
None
即可;如果特徵數非常多,根據情況調整,以控制決策樹的生成時間。
(2) max_depth
: 決策樹最大深度。
- 默認可以不輸入,則決策樹在建立子樹的時候不會限制子樹的深度。
- 一般來說,數據少或者特徵少時可以不管這個值。
- 如果模型樣本量多,特徵也多的情況下,常限制這個最大深度,具體的取值取決於數據的分佈。常用的可以取值10-100之間。
(3) min_samples_split
: 內部節點再劃分所需最小樣本數。
- 該值限制了子樹繼續劃分的條件,如果某節點的樣本數少於
min_samples_split
,則不會繼續再嘗試選擇最優特徵來進行劃分。 - 默認是 ,如果樣本量不大,不需要管這個值。若樣本量數量級非常大,則增大該值。
(4) min_samples_leaf
: 葉子節點最少樣本數。
- 該值限制了葉子節點最少的樣本數,若某葉子節點數目小於樣本數,則會和兄弟節點一起被剪枝。
- 默認是1,可以輸入最少的樣本數的整數,或者最少樣本數佔樣本總數的百分比。如果樣本量不大,不需要管這個值。如果樣本量數量級非常大,則推薦增大這個值。
(5) min_weight_fraction_leaf
:葉子節點最小的樣本權重和。
- 該值限制了葉子節點所有樣本權重和的最小值,如果小於這個值,則會和兄弟節點一起被剪枝。 默認是0,就是不考慮權重問題。
- 一般來說,若較多樣本有缺失值,或分類樹樣本的分佈類別偏差很大,就會引入樣本權重,這時我們就要注意這個值了。
(6) max_leaf_nodes
: 最大葉子節點數。
- 通過限制最大葉子節點數,可以防止過擬合,默認是
None
,即不限制最大的葉子節點數。如果加了限制,算法會建立在最大葉子節點數內最優的決策樹。 - 如果特徵不多,可以不考慮這個值,但是如果特徵分成多的話,可以加以限制,具體的值可以通過交叉驗證得到。
4、實戰
# -*- coding:utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import make_gaussian_quantiles
"""
1. 生成一些隨機數據,用於做二元分類
"""
# 生成2維正態分佈,生成的數據按分位數分爲兩類,200個樣本,2個樣本特徵,協方差係數爲2
X1, y1 = make_gaussian_quantiles(cov=2.,
n_samples=200, n_features=2,
n_classes=2, random_state=2019)
# 生成2維正態分佈,生成的數據按分位數分爲兩類,300個樣本,2個樣本特徵均值都爲3,協方差係數爲2
X2, y2 = make_gaussian_quantiles(mean=(3, 3), cov=1.5,
n_samples=300, n_features=2,
n_classes=2, random_state=2019)
# 將兩組數據合成一組數據
X = np.concatenate((X1, X2))
y = np.concatenate((y1, - y2 + 1))
"""
2. 基於決策樹的Adaboost來做分類擬合
"""
# 這裏我們選擇了SAMME算法,最多200個弱分類器,步長0.8
bdt = AdaBoostClassifier(DecisionTreeClassifier(max_depth=1),
algorithm="SAMME",
n_estimators=200)
bdt.fit(X, y)
"""
3. 擬合結果可視化
"""
plot_colors = "br"
plot_step = 0.02
class_names = "AB"
plt.figure(figsize=(10, 5))
# Plot the decision boundaries
plt.subplot(121)
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, plot_step),
np.arange(y_min, y_max, plot_step))
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.axis("tight")
# Plot the training points
for i, n, c in zip(range(2), class_names, plot_colors):
idx = np.where(y == i)
plt.scatter(X[idx, 0], X[idx, 1],
c=c, cmap=plt.cm.Paired,
s=20, edgecolor='k',
label="Class %s" % n)
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)
plt.legend(loc='upper right')
plt.xlabel('x')
plt.ylabel('y')
plt.title('Decision Boundary')
# Plot the two-class decision scores
twoclass_output = bdt.decision_function(X)
plot_range = (twoclass_output.min(), twoclass_output.max())
plt.subplot(122)
for i, n, c in zip(range(2), class_names, plot_colors):
plt.hist(twoclass_output[y == i],
bins=10,
range=plot_range,
facecolor=c,
label='Class %s' % n,
alpha=.5,
edgecolor='k')
x1, x2, y1, y2 = plt.axis()
plt.axis((x1, x2, y1, y2 * 1.2))
plt.legend(loc='upper right')
plt.ylabel('Samples')
plt.xlabel('Score')
plt.title('Decision Scores')
plt.tight_layout()
plt.subplots_adjust(wspace=0.35)
plt.show()
在下一篇中將介紹GDBT相關內容,敬請期待~