AdaBoost學習筆記

        學習了李航《統計學習方法》第八章的提高方法,如今對經常使用的一種提高方法AdaBoost做一個小小的筆記,並用python實現書本上的例子,加深印象。提高方法(boosting)是一種經常使用的統計學習方法,在分類中經過改變樣本的權值分佈,學習多個分類器,而後組合這些分類器,提升分類性能。python

1、 提高方法的問題

  一、訓練弱分類器時如何更改樣本權重或機率分佈
算法

  二、如何組合弱分類器app

AdaBoost的解決方案函數

  一、在訓練過程當中,提升前一輪被分類器錯誤分類的樣本權值,下降被正確分類的樣本權值性能

  二、採用加權多數表決的方法,即分類時偏差小的分類器權重提升,分類偏差大的分類器權重減少學習

2、AdaBoost算法步驟

  一、初始化訓練數據的權值分佈(初始化時通常賦予相同的權值:1/N);測試

  二、訓練弱分類器。根據具備權值分佈的訓練數據,獲得弱分類器,根據當前分類器,若是樣本點被正確分類,則下降該樣本的權值,反之提升權值,對樣本權值分佈進行更新,而後在根據更新後的樣本數據訓練下一個弱分類器;spa

  三、組合弱分類器。根據分類器訓練偏差,計算分類器的權重,偏差越大,權重越小,而後把加權後的分類器進行相加獲得強分類器。3d

下面是一個二分類算法code

算法: (輸入:訓練數據集T={(x1,y1),(x2,y2),..,(xN,yN))},輸出:最終分類器)

  (1)初始化訓練數據的權值分佈

 

  (2)訓練弱分類器。對於m=1,2,...,M (M爲弱分類器個數)

      (a) 使用具備權值分佈Dm的訓練數據集學習,獲得基本分類器

      (b) 計算Gm(x)在訓練數據集Dm上的分類偏差率:

    這裏至關於把沒有正確分類的樣本對應的權值求和

      (c) 計算Gm(x)的權重係數:

    這裏log表示天然對數,將am對em求導後能夠獲得對應的導函數爲1/(em-1)em,偏差0<em<1,因此對應的導函數小於0,即係數am隨着偏差em的增大而減小。

      (d) 更新訓練數據集權值分佈:

  

    這裏Zm是對權值進行歸一化,保證權值和爲1,另外樣本若是正確分類,則yi*Gm(xi)爲一個正數,前面添加負號和乘以am,這能夠看出正確分類的樣本其權值下降,錯誤分類的樣本權值提升。

  (3)構建基本分類器的線性組合,獲得最終分類器

 

3、例題(python實現)

  一、初始化權值分佈

## 導入數據
import numpy as np
x = np.arange(10)  # x共10個,利用numpy生成
y = np.array([1,1,1,-1,-1,-1,1,1,1,-1], dtype=int)  #例題中對應的標籤值

## 權值初始化,一共10個數,初始權值賦爲1/10
N = x.shape[0]
w_0 = np.array([1/N]*N)  #先計算1/N,而後乘以個數
w_0

 

  二、x1和x2之間的閥值取x1+(x2-x1)*b,x之間間隔爲1,所以0<b<1都行,這裏參照書本取b=0.5

# 獲得全部閥值,存入列表
v = np.array([(x1+x2)/2 for x1, x2 in zip(x[:-1], x[1:])])
v

  三、訓練一個弱分類器

# 定義一個分類函數 輸入:樣本數據x,y,閥值v,權重w   輸出:最佳閥值min_v,該分類器分類結果res,和權重alpha,以及偏差min_error

def get_res(x,y,v,w):
    error_1 = []  # 用於存放全部閥值分類獲得的偏差
    error_2 = []
    res_1 = np.ones(x.shape[0], dtype=int) # 先初始化結果全爲1  小於閥值取1,大於取-1
    res_2 = np.ones(x.shape[0], dtype=int) # 先初始化結果全爲1  小於閥值取-1,大於取1
    for v_i in v:   # 對每個閥值計算分類偏差
        for x_i in x:
            if x_i < v_i:
                res_1[x_i] = 1
                res_2[x_i] = -1
            else:
                res_1[x_i] = -1
                res_2[x_i] = 1
        error_1.append(np.sum(w[y!=res_1]))
        error_2.append(np.sum(w[y!=res_2]))
    min_error_1 = min(error_1)  # 最小偏差
    min_error_2 = min(error_2)  
    if min_error_1 > min_error_2:
        min_error = min_error_2
        min_error_index = error_2.index(min_error_2)  # 求出最小偏差對應的索引值,用於找出最佳閥值
        label = '小於取-1,大於取1'
        state = 0  # 用於判斷分類器怎麼分類 求res
    else:
        min_error = min_error_1
        min_error_index = error_1.index(min_error_1)
        label = '小於取1,大於取-1'
        state = 1
    min_v = v[min_error_index] # 獲得最佳閥值
    alpha = 1/2 * np.log((1-min_error)/min_error) # 計算該分類器的權值
    if state == 1:
        res = [1 if x_i < min_v else -1 for x_i in x]  # 計算該分類器分類結果
    else:
        res = [-1 if x_i < min_v else 1 for x_i in x]
    return alpha, min_v, label, res, min_error
## 輸入初始權值,進行測試
alpha1, v1, label, res1, min_error = get_res(x,y,v,w_0)
v1,label,alpha1,res1,min_error

  四、更新樣本數據權值分佈

### 定義一個更新函數 輸入:前一個分類器的權重alpha和分類結果res 樣本標籤y, 前一次樣本權值分佈w  輸出:樣本數據新的權值分佈w
def update_data_weight(alpha, res, y, w):
    numerator = w*np.exp(-alpha*y*res)  # 8.4式分子
    denominator = w.dot(np.exp(-alpha*y*res))  # 8.4式分母Zm 
    return numerator/denominator
## 測試
w_1 = update_data_weight(alpha1, res1, y, w_0)
w_1

  五、構建最終分類器

## alpha 各弱分類器權重列表
## res 各弱分類器分類結果列表

def final_model(alpha, res):
f = np.sum(alpha*res, axis=0)
return [1 if i > 0 else -1 for i in f]

  這裏在對其進行綜合,代碼以下。

n = 3  # 弱分類器個數1
sigmma = 0.001  # 終止偏差

x = np.arange(10)  # 樣本中x值
y = np.array([1,1,1,-1,-1,-1,1,1,1, -1], dtype=int)  # 樣本中x對應的標籤值

N = x.shape[0]  # 樣本個數

alpha = np.zeros((n, 1))  # 初始化分類器權重矩陣
W = np.zeros((n, N))  # 初始化權值分佈
res = np.zeros((n, N))  # 初始化各分類器結果
res_save = []  # 保存每一次的閥值和偏差

w = np.array([1/N]*N)  # 樣本初始權值分佈

v = np.array([(x1+x2)/2 for x1, x2 in zip(x[:-1], x[1:])])  # 全部閥值

for i in range(n):
    alpha_i, v_i, label, res_i, min_error_i = get_res(x,y,v,w)
    
    if min_error_i < sigmma:  # 若是知足偏差要求 中止迭代
        break
    w = update_data_weight(alpha_i, res_i, y, w)
    alpha[i] = alpha_i
    res[i:] = res_i
    res_save.append([v_i, label, min_error_i])
    W[i:] = w

result = final_model(alpha, res)
print('最終分類結果:', result)
print('各分類器分類結果:', res)
print('各分類器係數:', alpha)
print('各分類器閥值及偏差:',res_save)
print('樣本權值分佈:',W)

相關文章
相關標籤/搜索