前言
前面的文章中介紹了決策樹以及其它一些算法,但是,會發現,有時候使用使用這些算法並不能達到特別好的效果。於是乎就有了集成學習
(Ensemble Learning),通過構建多個學習器一起結合來完成具體的學習任務。這篇文章將介紹集成學習,以及其中的一種算法 AdaBoost。
集成學習
首先先來介紹下什么是集成學習:
- 構建多個學習器一起結合來完成具體的學習任務,常可獲得比單一學習器顯著優越的泛化性能,對“弱學習器” 尤為明顯(三個臭皮匠,頂個諸葛亮)
- 也稱為
Multi-Classifier System
,Committee-Based Learning
- 學習器可以是同類型的,也可以是不同類型
這么一看,就感覺集成學習與常說的模型融合很像,甚至可以理解為就是模型融合。
那么,常用的集成學習方法有哪些呢?
- Boosting,將各種弱分類器串聯起來的集成學習方式,每一個分類器的訓練都依賴於前一個分類器的結果,代表:AdaBoost,Gradient Boosting Machine
- Bagging,Bootstrap Aggregating 的縮寫。這種方法采用的是隨機有放回的選擇訓練數據然后構造分類器,最后進行組合,代表:Random Forest
- Voting/Averaging,在不改變模型的情況下,直接對各個不同的模型預測的結果進行投票或者平均
- Binning,最近看到的一種方法,還沒細看,參考論文
- Stacking
- Blending
后面幾種方法這里暫時不做介紹,后面會單獨寫博客來介紹這些方法
AdaBoost
算法思想
這里將介紹一個基於 Boosting 方法的一個學習算法 AdaBoost,於1995年由 Freund 和 Schapire 提出。其主要思想為:
- 先訓練出一個基學習器
- 根據該學習器的表現對訓練樣本權重進行調整,使得現有基學習器做錯的樣本在后續學習器的訓練中受到更多的關注
- 基於調整后的權重來訓練下一個基學習器
- 重復 2、3 直至學習器數目達到事先指定的值 T
- 最終將這 T 個學習器進行加權結合
具體算法
設訓練數據集
初始化訓練數據的權值分布
for t in range(T):
假設訓練得到分類器 \(h_t(x)\) ,則可計算 \(h_t(x)\) 在當前訓練集上的分類誤差:
若 \(\epsilon_{t} > 0.5\), break; 否則計算分類器權重
然后更新樣本權重
其中 \(Z_t\) 為歸一化因子
構建基本分類器的線性組合
得到最終分類器
這里我們可以看到 \(\alpha_t\) 是大於 $\frac{1}{2} $ 的,如果誤分類了,那么 \(-\alpha_{t} y^{(i)} h_{t}\left(x^{(i)}\right)\) 為大於 0 的數,那么樣本的權重就會被放大,反之,則會被縮小。並且, \(\epsilon_t\) 越大,\(\alpha_t\) 就越小,即在最終構建強分類器的時候,誤差率越小的弱分類器預測結果所占比重越高。
算法推導
思考兩個個問題, \(\alpha_t\) 的公式是怎么來的?以及權重更新公式是怎么來的?下面通過公式推導來講解
假設已經經過 \(t-1\) 輪迭代,得到\(f_{t-1}(x)\),根據前向分布加法算法
目標是損失函數最小,即
所以,有
我們先來化簡損失函數
仔細以看,后面那項 \(\frac{\sum_{y_i \ne h_t(x_i)}w_{t,i}}{\sum_{i=1}^{N}w_{t,i}}\) 就是分類誤差率 \(\epsilon_{t}\),所以
對 \(\alpha_t\) 求偏導
令 \(\frac{\partial Loss}{\partial \alpha_t} = 0\) ,則
推得
另,由前向分布加法算法
再加上規范化因子即為算法中的更新公式。(公式敲的要累死了~~~)
代碼實現
這里為了方便起見,我使用了 sklearn 里面的決策樹,之前使用的時候一直沒發現 sklearn 里的決策樹可以帶權重訓練 orz。。。決策樹帶權訓練的代碼我后面再研究研究
from sklearn.tree import DecisionTreeClassifier
def adaboost(X, y, M, max_depth=None):
"""
adaboost函數,使用Decision Tree作為弱分類器
參數:
X: 訓練樣本
y: 樣本標簽, y = {-1, +1}
M: 使用 M 個弱分類器
max_depth: 基學習器決策樹的最大深度
返回:
F: 生成的模型
"""
num_X, num_feature = X.shape
# 初始化訓練數據的權值分布
D = np.ones(num_X) / num_X
G = []
alpha = []
for m in range(M):
# 使用具有權值分布 D 的訓練數據集學習,得到基本分類器
# 使用 DecisionTreeClassifier,設置樹深度為 max_depth
G_m = DecisionTreeClassifier(max_depth=max_depth)
# 開始訓練
G_m.fit(X, y, D)
# 計算G_m在訓練數據集上的分類誤差率
y_pred = G_m.predict(X)
e_m = np.sum(D[y != y_pred])
if e_m == 0:
break
if e_m == 1:
raise ValueError("e_m = {}".format(e_m))
# 計算 G_m 的系數
alpha_m = np.log((1 - e_m) / e_m) / 2
# print(alpha_m)
# 更新訓練數據集的權值分布
D = D * np.exp(-alpha_m * y * y_pred)
D = D / np.sum(D)
# 保存 G_m 和其系數
G.append(G_m)
alpha.append(alpha_m)
# 構建基本分類器的線性組合
def F(X):
num_G = len(G)
score = 0
for i in range(num_G):
score += alpha[i] * G[i].predict(X)
return np.sign(score)
return F
小節
上面介紹了集成學習的一些知識點以及 AdaBoost 的基本原理及實現,下一篇將介紹集成學習中基於 Bagging 的隨機森林(Random Forest)。