談談模型融合之一 —— 集成學習與 AdaBoost

前言

前面的文章中介紹了決策樹以及其它一些算法,可是,會發現,有時候使用使用這些算法並不能達到特別好的效果。因而乎就有了集成學習(Ensemble Learning),經過構建多個學習器一塊兒結合來完成具體的學習任務。這篇文章將介紹集成學習,以及其中的一種算法 AdaBoost。python

集成學習

首先先來介紹下什麼是集成學習:web

  • 構建多個學習器一塊兒結合來完成具體的學習任務,常可得到比單一學習器顯著優越的泛化性能,對「弱學習器」 尤其明顯(三個臭皮匠,頂個諸葛亮)
  • 也稱爲Multi-Classifier System, Committee-Based Learning
  • 學習器能夠是同類型的,也能夠是不一樣類型

這麼一看,就感受集成學習與常說的模型融合很像,甚至能夠理解爲就是模型融合。算法

那麼,經常使用的集成學習方法有哪些呢?spring

  1. Boosting,將各類弱分類器串聯起來的集成學習方式,每個分類器的訓練都依賴於前一個分類器的結果,表明:AdaBoost,Gradient Boosting Machine
  2. Bagging,Bootstrap Aggregating 的縮寫。這種方法採用的是隨機有放回的選擇訓練數據而後構造分類器,最後進行組合,表明:Random Forest
  3. Voting/Averaging,在不改變模型的狀況下,直接對各個不一樣的模型預測的結果進行投票或者平均
  4. Binning,最近看到的一種方法,還沒細看,參考論文
  5. Stacking
  6. Blending

後面幾種方法這裏暫時不作介紹,後面會單獨寫博客來介紹這些方法api

AdaBoost

算法思想

這裏將介紹一個基於 Boosting 方法的一個學習算法 AdaBoost,於1995年由 Freund 和 Schapire 提出。其主要思想爲:app

  1. 先訓練出一個基學習器
  2. 根據該學習器的表現對訓練樣本權重進行調整,使得現有基學習器作錯的樣本在後續學習器的訓練中受到更多的關注
  3. 基於調整後的權重來訓練下一個基學習器
  4. 重複 二、3 直至學習器數目達到事先指定的值 T
  5. 最終將這 T 個學習器進行加權結合

\[ H(x)=\operatorname{sign}\left(\sum_{t=1}^{T} \alpha_{t} h_{t}(x)\right) \]dom

具體算法

設訓練數據集
\[ \{x^{(i)}, y^{(i)}\}_{i=1}^{m},x^{(i)} \in \mathbb{R}^n, y \in \{-1, +1\} \]
初始化訓練數據的權值分佈
\[ \mathcal{D}_{1}\left(x^{(i)}\right)=\frac{1}{m} \]
for t in range(T):函數

​ 假設訓練獲得分類器 \(h_t(x)\) ,則可計算 \(h_t(x)\) 在當前訓練集上的分類偏差:
\[ \epsilon_{t}=P_{x \sim \mathcal{D}_{t}}\left[h_{t}(x) \neq y\right]=\sum_{y^{(i)} \neq h_{t}\left(x^{(i)}\right)} \mathcal{D}_{t}\left(x^{(i)}\right) \]
​ 若 \(\epsilon_{t} > 0.5\), break; 不然計算分類器權重
\[ \alpha_{t}=\frac{1}{2} \log \frac{1-\epsilon_{t}}{\epsilon_{t}} \]
​ 而後更新樣本權重
\[ \mathcal{D}_{t+1}\left(x^{(i)}\right)=\frac{1}{Z_{t}} \mathcal{D}_{t}\left(x^{(i)}\right) \exp \left[-\alpha_{t} y^{(i)} h_{t}\left(x^{(i)}\right)\right] \]
​ 其中 \(Z_t\) 爲歸一化因子
\[ Z_{t}=\sum_{i} \mathcal{D}_{t}\left(x^{(i)}\right) \exp \left[-\alpha_{t} y^{(i)} h_{t}\left(x^{(i)}\right)\right] \]
構建基本分類器的線性組合
\[ f(x)=\sum_{t=1}^{T} \alpha_{t} h_{t}(x) \]
獲得最終分類器
\[ H(x)=\operatorname{sign}\left(\sum_{t=1}^{T} \alpha_{t} h_{t}(x)\right) \]性能

這裏咱們能夠看到 \(\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)\),根據前向分佈加法算法
\[ f_t(x) = f_{t-1}(x) + \alpha_{t}h_t(x) \]
目標是損失函數最小,即
\[ \min{Loss} = \min\sum_{i=1}^{N}exp[-y_i(f_{t-1}(x_i)+\alpha_th_t)] \]
因此,有
\[ \begin{eqnarray}(\alpha_t,h_t(x)) & = & \arg {\min_{\alpha,h}\sum_{i=1}^{N}exp[-y_i(f_{t-1}(x_i)+\alpha_th_t()x_i)]} \\ & = & \arg {\min_{\alpha,h}\sum_{i=1}^{N}w_{t,i}exp[-y_i(\alpha_th_t(x_i))]} \end{eqnarray} \]

\[ w_{t,i} = \exp[-y_if_{t-1}(x_i)] \]

咱們先來化簡損失函數
\[ \begin{eqnarray}Loss & = &\sum_{y_i=h_t(x_i)}w_{t,i}exp(-\alpha_t)+\sum_{y_i \ne h_t(x_i)}w_{t,i}exp(\alpha_t) \\ & = & \sum_{i=1}^{N}w_{t,i}(\frac{\sum_{y_i=h_t(x_i)}w_{t,i}}{\sum_{i=1}^{N}w_{t,i}}exp(-\alpha_t)+\frac{\sum_{y_i \ne h_t(x_i)}w_{t,i}}{\sum_{i=1}^{N}w_{t,i}}exp(-\alpha_t)) \end{eqnarray} \]
仔細以看,後面那項 \(\frac{\sum_{y_i \ne h_t(x_i)}w_{t,i}}{\sum_{i=1}^{N}w_{t,i}}\) 就是分類偏差率 \(\epsilon_{t}\),因此
\[ Loss = \sum_{i=1}^{N}w_{t,i}[(1-\epsilon_t)exp(-\alpha_t)+\epsilon_texp(\alpha_t)] \]
\(\alpha_t\) 求偏導
\[ \begin{eqnarray} \frac{\partial Loss}{\partial \alpha_t} & = & \sum_{i=1}^{N}w_{t,i}[-(1-\epsilon_t)exp(-\alpha_t)+\epsilon_texp(\alpha_t)] \end{eqnarray} \]
\(\frac{\partial Loss}{\partial \alpha_t} = 0\) ,則
\[ -(1-\epsilon_t)exp(-\alpha_t)+\epsilon_texp(\alpha_t) = 0 \]
推得
\[ \alpha_{t}=\frac{1}{2} \log \frac{1-\epsilon_{t}}{\epsilon_{t}} \]
另,由前向分佈加法算法
\[ \begin{eqnarray} w_{t,i} & = & \exp[-y_if_{t-1}(x_i)] \\ & = & \exp[-y_i(f_{t-2}(x_i)+\alpha_{t-1}h_{t-1}(x_i))] \\ & = & w_{t-1,i}\exp[\alpha_{t-1}h_{t-1}(x_i)] \end{eqnarray} \]
再加上規範化因子即爲算法中的更新公式。(公式敲的要累死了~~~)

代碼實現

這裏爲了方便起見,我使用了 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)。

相關文章
相關標籤/搜索