AdaBoost元算法

項目代碼

元算法

元算法(meta-algorithm)是對其他算法進行組合的一種方式。(或稱集成方法,ensemble method)
集成方法的不同形式:

  1. 不同算法的集成
  2. 同一算法在不同設置下的集成
  3. 數據集不同部分分配給不同分類器之後的集成
  4. 基於同一種分類器在多個不同實例下的集成

bagging:基於數據隨機重抽樣的分類器構建方法

bagging也稱自舉匯聚法(bootstrap aggregating)。
核心思想:假設訓練集有NN個樣本,從中隨機抽取SS次,每次有放回的獲取MM個樣本,用某個單獨的算法對SS個數據集(每個數據集有MM個樣本)進行訓練,這樣就可以獲得SS個分類器,最後通過投票來獲取最後的結果。
隨機森林(Random Forest,RF)是bagging方法的一種,其基於決策樹,不僅對數據隨機化抽取,也對特徵隨機化抽取。
1. 數據的隨機化:利用bootstrap方法有放回地隨機抽取SS個新的樣本集。
2. 特徵隨機化nn個特徵,每棵樹隨機選擇mm個特徵劃分數據集。

boosting

boosting方法是先在原數據集上訓練出一個分類器,然後將前一個分類器沒能完美分類的數據樣本重新賦權重(weight),用新的權重數據樣本再訓練出一個分類器,以此循環,最終的分類結果由加權投票決定。

  1. boosting和bagging均使用單個學習算法。
  2. boosting是串行算法(必須依賴上一個分類器),bagging是並行算法(可以同時進行);
  3. boosting的分類器權重不同,bagging相同。

boosting:AdaBoost

AdaBoost是boosting最流行的一個版本。
AdaBoost的基礎理論:使用弱分類器和多個實例構建一個強分類器,弱意味着分類器的性能比隨機猜測的要略好,但不會好太多,而強分類器的錯誤率要低很多。
AdaBoost的算法流程:

  1. 給每個訓練樣本賦權重,這些權重構成向量DD(初始權重相等,如1000個數據,那每個數據樣本初始權重爲1/1000)。
  2. 在該數據上訓練一個弱分類器並計算錯誤率和該分類器的權重值α\alpha(基於每個弱分類器的錯誤率進行計算)。
  3. 基於該α\alpha值重新計算權重(分錯的樣本權重變大,分對的權重變小)。
  4. 循環2,3步,在完成給定的迭代次數或錯誤閾值時,停止循環。
  5. 最終的分類結果由加權投票決定。
    錯誤率
    ε=\varepsilon=\frac{分類錯誤的樣本數}{所有樣本數目}
    α\alpha值的計算
    α=12ln1εε\alpha=\frac{1}{2}ln\frac{1-\varepsilon}{\varepsilon}
    AdaBoost算法示意圖(來源機器學習是實戰):
    在這裏插入圖片描述
    計算出α\alpha值後,可以對權重向量DD進行更新,以使得那些正確分類的樣本的權重降低而分錯樣本的權重增大。
    樣本正確分類,其權重修改爲:
    Dt(t+1)=Dt(t)eα(D)D_t^{(t+1)}=\frac{D_t^{(t)}e^{-\alpha}}{\sum(D)}
    樣本被錯誤分類,其權重修改爲:
    Dt(t+1)=Dt(t)eα(D)D_t^{(t+1)}=\frac{D_t^{(t)}e^{\alpha}}{\sum(D)}

基於單層決策樹構建弱分類器

加載數據:

import numpy as np
import matplotlib.pyplot as plt


def read_data():
    data = np.array([[1, 2.1], [2, 1.1], [1.3, 1], [1, 1], [2, 1]])
    label = [1, 1, -1, -1, 1]
    return data,label


if __name__ =="__main__":
    data,label = read_data()
    x =data[:,0]
    y =data[:,1]
    # print(x)
    plt.scatter(x,y,c=label)
    plt.show()```
構建單層決策樹:

```python
import numpy as np


def stump_classify(x, dim, thresh_val, thresh_ineq):
    '''
    通過閾值比較對數據進行分類。
    所有在閾值一邊的數據會分到類別-1,而另一邊的數據會被分類到+1。
    通過數組過濾實現。
    '''
    retArray = np.ones((x.shape[0], 1))
    if thresh_ineq == 'lt':
        retArray[x[:, dim] <= thresh_val] = -1
    else:
        retArray[x[:, dim] > thresh_val] = -1
    return retArray


def build_stump(x, y, D):
    '''

    :param x: 輸入數據
    :param y: 輸入數據的標籤
    :param D: 權重向量
    :return:
    '''
    x_mat = np.matrix(x)  # 轉換成矩陣形式
    y_mat = np.matrix(y).T
    m, n = x.shape
    num_steps = 10
    best_stump = {}
    best_class_est = np.matrix(np.zeros((m, 1)))
    min_err = np.inf
    for i in range(n):  # 遍歷所有特徵
        row_min = x_mat[:, i].min()
        row_max = x_mat[:, i].max()
        step_size = (row_max - row_min) / num_steps
        for j in range(-1, num_steps + 1):
            for eq in ['lt', 'gt']:
                thresh_val = row_min + j * step_size
                pre_val = stump_classify(x, i, thresh_val, eq)
                err_arr = np.matrix(np.ones((m, 1)))
                err_arr[pre_val == y_mat] = 0
                weight_err = D.T * err_arr
                print("split: dim %d, thresh %.2f, thresh ineqal: %s, "
                      "the weighted error is %.3f"
                      % (i, thresh_val, eq, weight_err))
                if weight_err < min_err:
                    min_err = weight_err
                    best_class_est = pre_val.copy()
                    best_stump['dim'] = i
                    best_stump['thresh'] = thresh_val
                    best_stump['ineq'] = eq

        return best_stump, min_err, best_class_est

分類實現代碼:

import numpy as np
from stump import *


def adaboost_trian(x, y, num_it=40):
    week_class_arr = []
    m = x.shape[0]
    D = np.matrix(np.ones((m, 1)) / m)  # 初始化權重向量D
    agg_class_est = np.matrix(np.zeros((m, 1)))
    for i in range(num_it):
        best_stump, err, class_est = build_stump(x, y, D)
        print('D: ', D.T)
        alpha = 0.5 * np.log((1 - err) // max(err, 1e-16))  # 計算alpha值
        best_stump['alpha'] = alpha
        week_class_arr.append(best_stump)
        print('class_est: ', class_est.T)
        expon = np.multiply(np.matrix(-1 * alpha * y).T, class_est)
        D = np.multiply(D, np.exp(expon))
        D = D / np.sum(D)
        agg_class_est += np.multiply(alpha, class_est)
        print('agg_class_est: ', agg_class_est.T)
        agg_err = np.multiply(np.sign(agg_class_est) != np.matrix(y).T, np.ones((m, 1)))
        err_rate = np.sum(agg_err) / m
        print('total error: ', err_rate, '\n')
        if err_rate == 0:
            break
    return week_class_arr


def adaClassify(test, classifierArr):
    dataMatrix = np.matrix(test)  # do stuff similar to last aggClassEst in adaBoostTrainDS
    m = dataMatrix.shape[0]
    aggClassEst = np.matrix(np.zeros((m, 1)))
    for i in range(len(classifierArr)):
        classEst = stump_classify(dataMatrix, classifierArr[i]['dim'],
                                  classifierArr[i]['thresh'],
                                  classifierArr[i]['ineq'])  # call stump classify
        aggClassEst += np.multiply(classifierArr[i]['alpha'], classEst)
        print(aggClassEst)
    return np.sign(aggClassEst)

測試代碼:

from adaboost import adaboost_trian,adaClassify
from load_data import read_data

if __name__ =='__main__':
    data,label = read_data()
    classifier_array = adaboost_trian(data,label,9)
    # print(classifier_array)
    re = adaClassify([[5,5],[0,0]],classifier_array)
    print(re)```

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