整合學習(1)AdaBoost分別應用於分類和迴歸及其python實現

Donreen發表於2020-12-03


前言:近期在做比賽的時候建模階段普遍都是使用整合模型效果更好,如xgboost、lgb、catboost等,但是對其中原理並不瞭解,所以準備從adaboost開始慢慢學習這一系列的整合模型…

1.AdaBoost分類

整合模型主要有bagging和boosting兩種,這裡都是boosting類的。

1.1Boosting基本思路

  1. 先用每個樣本權重相等的訓練集訓練一個初始的基學習器。
  2. 根據上輪得到的學習器對訓練集的預測表現情況調整訓練集中的樣本權重,然後據此訓練一個新的基學習器。
  3. 重複上面的步驟2得到M個基學習器,最終的整合結果就是這M個基學習器的組合。

上面的步驟很明顯是一個序列的過程,並且所使用到的基學習器都是比較簡單的。

1.2AdaBoost分類的基本思路

  1. 提高上一輪被錯誤分類的樣本的權值,降低被正確正確分類的樣本權值。
  2. 在最後整合結果線性加權求和過程中,誤差率小的基學習器擁有更大的權值,誤差率大的基學習器擁有較小的權值。

其中第二步整合的思想也經常用於模型融合。

1.3AdaBoost的演算法步驟

首先假設樣本數量為N,基學習器的數目為M。

  1. 初始化樣本權重: D 1 = ( w 11 , w 12 , . . . , w 1 N ) , w 1 i = 1 N , i = 1 , 2 , . . . , N D_1=(w_{11},w_{12},...,w_{1N}), w_{1i}=\frac{1}{N},i=1,2,...,N D1=(w11,w12,...,w1N),w1i=N1,i=1,2,...,N
  2. m = 1 , 2 , . . . , M m=1,2,...,M m=1,2,...,M重複以下操作得到M個基學習器:
    (1)按照樣本權重分佈 D m D_m Dm訓練資料得到第 m m m個基學習器 G m ( x ) G_m(x) Gm(x);
    (2)計算 G m ( x ) G_m(x) Gm(x)在加權訓練資料集上的分類誤差率: e m = ∑ i = 1 N D ( G m ( x i ) ≠ y i ) = ∑ i = 1 N w m , i I ( G m ( x i ) ≠ y i ) e_m=\sum_{i=1}^ND(G_m(x_i)\neq y_i)=\sum_{i=1}^Nw_{m,i}I(G_m(x_i)\neq y_i) em=i=1ND(Gm(xi)=yi)=i=1Nwm,iI(Gm(xi)=yi)
    (3)計算 G m ( x ) G_m(x) Gm(x)的係數(即最終整合的基學習器的權重): α m = 1 2 l o g ( 1 − e m e m ) \alpha_m=\frac{1}{2}log(\frac{1-e_m}{e_m}) αm=21log(em1em),可以看到誤差率 e m e_m em越大,基學習器權重 α m \alpha_m αm越小。
    (4)更新樣本權重: D m + 1 = ( w m , 1 , w m , 2 , . . . , w m , N ) D_{m+1}=(w_{m,1},w_{m,2},...,w_{m,N}) Dm+1=(wm,1,wm,2,...,wm,N) w m + 1 , i = w m , i Z m e x p ( − α m y i G m ( x i ) ) , i = 1 , 2 , . . . , N w_{m+1,i}=\frac{w_{m,i}}{Z_m}exp(-\alpha_my_iG_m(x_i)),i=1,2,...,N wm+1,i=Zmwm,iexp(αmyiGm(xi)),i=1,2,...,N。其中 Z m Z_m Zm是規範化因子,目的就是為了使 D m + 1 D_{m+1} Dm+1得所有元素之和為1, Z m = ∑ i = 1 N w m , i e x p ( − α m y i G m ( x i ) ) Z_m=\sum_{i=1}^{N}w_{m,i}exp(-\alpha_my_iG_m(x_i)) Zm=i=1Nwm,iexp(αmyiGm(xi))。可以看到當分類錯誤時, y i G m ( x i ) = − 1 y_iG_m(x_i)=-1 yiGm(xi)=1,對應的權值增加。
  3. 構建最終的分類器線性組合: f ( x ) = ∑ m = 1 M α m G m ( x ) f(x)=\sum_{m=1}^M\alpha_mG_m(x) f(x)=m=1MαmGm(x),分類器 G ( x ) = s i g n ( f ( x ) ) G(x)=sign(f(x)) G(x)=sign(f(x))

1.4AdaBoost演算法的解釋

在上面演算法步驟中可以看到基學習器權重 α m \alpha_m αm得更新公式和樣本權重 w m w_m wm的更新公式是符合基本思路的,但是對於為什麼是要這麼更新?我們可以從另一個角度出發,把AdaBoost看作模型是加法模型、損失函式是指數損失函式、學習演算法為前向分步演算法的二分類學習方法

(1)首先看一下前向分步演算法的基本思想(這裡為了一般化,用其他符號進行表示):
對於我們的加法模型: f ( x ) = ∑ m = 1 M β m b ( x ; γ m ) f(x)=\sum_{m=1}^M\beta_mb(x;\gamma_m) f(x)=m=1Mβmb(x;γm), 其中 b ( x ; γ m ) b(x;\gamma_m) b(x;γm)是基函式, γ m \gamma_m γm是基函式的引數, β m \beta_m βm是基函式的係數;在給定損失函式 L ( y , f ( x ) ) L(y,f(x)) L(y,f(x))的條件下,學習加法模型的過程就是最小化損失函式: m i n ∑ i = 1 N L ( y i , ∑ m = 1 M β m b ( x ; γ m ) ) min\sum_{i=1}^NL(y_i,\sum_{m=1}^M\beta_mb(x;\gamma_m)) mini=1NL(yi,m=1Mβmb(x;γm)),而這個最優化的過程通常比較複雜,前向分佈演算法解決這個優化問題的思想就是每次只學習一個基函式,然後再用學習得到的這個基函式更新我們的加法模型。

(2)演算法步驟:
輸入訓練集 T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x N , y N ) } T=\{(x_1,y_1), (x_2,y_2),...,(x_N,y_N)\} T={(x1,y1),(x2,y2),...,(xN,yN)};損失函式 L ( y , f ( x ) ) L(y,f(x)) L(y,f(x));基函式集 { b ( x ; γ ) } \{b(x;\gamma)\} {b(x;γ)}

  1. 初始化 f 0 ( x ) = 0 f_0(x)=0 f0(x)=0
  2. m = 1 , 2 , . . . , M m=1,2,...,M m=1,2,...,M
    (1)極小化損失函式: ( β m , γ m ) = a r g m i n β , γ ∑ i = 1 N L ( y i , f m − 1 ( x i ) + β b ( x ; γ ) ) (\beta_m,\gamma_m)=argmin_{\beta,\gamma}\sum_{i=1}^{N}L(y_i,f_{m-1}(x_i)+\beta b(x;\gamma)) (βm,γm)=argminβ,γi=1NL(yi,fm1(xi)+βb(x;γ)),得到第m個基函式引數
    (2)更新加法模型: f m ( x ) = f m − 1 ( x ) + β m b ( x ; γ m ) f_m(x)=f_{m-1}(x)+\beta_mb(x;\gamma_m) fm(x)=fm1(x)+βmb(x;γm)
  3. 得到加法模型: f ( x ) = f M ( x ) = ∑ m = 1 M β m b ( x ; γ m ) f(x)=f_M(x)=\sum_{m=1}^M\beta_mb(x;\gamma_m) f(x)=fM(x)=m=1Mβmb(x;γm)

我們在1.3中得到的加法分類器也是這樣的一個加法模型,所以也可以使用前向分步演算法來進行求解。

(3)具體推導:
首先基於前向分步演算法的思想和AdaBoost得到的加法模型,AdaBoost可以看作前向分步演算法的一個特例,其基函式為基本分類器 G ( x ) G(x) G(x),損失函式為指數損失函式 L ( y , f ( x ) ) = e x p ( − y f ( x ) ) L(y,f(x))=exp(-yf(x)) L(y,f(x))=exp(yf(x))。結合上面的演算法步驟,假設前m-1輪已經得到 f m − 1 ( x ) f_{m-1}(x) fm1(x),我們的第m輪的優化目標如下:
a r g m i n α m , G m ∑ i = 1 N L ( y i , f m − 1 ( x i ) + α m G m ( x i ) ) ⇒ a r g m i n α m , G m ∑ i = 1 N e x p [ − y i ( f m − 1 ( x i ) + α m G m ( x i ) ) ] ⇒ a r g m i n α m , G m ∑ i = 1 N e x p [ − y i f m − 1 ( x i ) ] e x p [ − y i α m G m ( x i ) ] argmin_{\alpha_m,G_m}\sum_{i=1}^{N}L(y_i,f_{m-1}(x_i)+\alpha_m G_m(x_i))\\\Rarr argmin_{\alpha_m,G_m}\sum_{i=1}^{N}exp[-y_i(f_{m-1}(x_i)+\alpha_m G_m(x_i))]\\\Rarr argmin_{\alpha_m,G_m}\sum_{i=1}^{N}exp[-y_if_{m-1}(x_i)]exp[-y_i\alpha_m G_m(x_i)] argminαm,Gmi=1NL(yi,fm1(xi)+αmGm(xi))argminαm,Gmi=1Nexp[yi(fm1(xi)+αmGm(xi))]argminαm,Gmi=1Nexp[yifm1(xi)]exp[yiαmGm(xi)]
因為 y i y_i yi f m − 1 ( x ) f_{m-1}(x) fm1(x)已經得到,所以可以令 w m , i = e x p [ − y i f m − 1 ( x i ) ] w_{m,i}=exp[-y_if_{m-1}(x_i)] wm,i=exp[yifm1(xi)],然後上面的優化目標變成如下形式:
a r g m i n α m , G m ∑ i = 1 N w m , i e x p [ − y i α m G m ( x i ) ] ⇒ a r g m i n α m , G m ∑ y i = G m ( x i ) w m , i e − α m + ∑ y i ≠ G m ( x i ) w m , i e α m ⇒ a r g m i n α m , G m ( e α m − a − α m ) ∑ i = 1 N w m , i I ( y i ≠ G m ( x i ) ) + e − α m ∑ i = 1 N w m , i argmin_{\alpha_m,G_m}\sum_{i=1}^{N}w_{m,i}exp[-y_i\alpha_m G_m(x_i)]\\\Rarr argmin_{\alpha_m,G_m}\sum_{y_i=G_m(x_i)}w_{m,i}e^{-\alpha_m}+\sum_{y_i\neq G_m(x_i)}w_{m,i}e^{\alpha_m}\\\Rarr argmin_{\alpha_m,G_m}(e^{\alpha_m}-a^{-\alpha_m})\sum_{i=1}^Nw_{m,i}I(y_i\neq G_m(x_i))+e^{-\alpha_m}\sum_{i=1}^Nw_{m,i} argminαm,Gmi=1Nwm,iexp[yiαmGm(xi)]argminαm,Gmyi=Gm(xi)wm,ieαm+yi=Gm(xi)wm,ieαmargminαm,Gm(eαmaαm)i=1Nwm,iI(yi=Gm(xi))+eαmi=1Nwm,i
然後上式關於 α m \alpha_m αm求導,並令其為0:
( e α m + a − α m ) ∑ i = 1 N w m , i I ( y i ≠ G m ( x i ) ) − e − α m ∑ i = 1 N w m , i = 0 ⇒ ∑ i = 1 N w m , i I ( y i ≠ G m ( x i ) ) ∑ i = 1 N w m , i = e − α m ( e α m + a − α m ) (e^{\alpha_m}+a^{-\alpha_m})\sum_{i=1}^Nw_{m,i}I(y_i\neq G_m(x_i))-e^{-\alpha_m}\sum_{i=1}^Nw_{m,i}=0\\\Rarr \frac{\sum_{i=1}^Nw_{m,i}I(y_i\neq G_m(x_i))}{\sum_{i=1}^Nw_{m,i}}=\frac{e^{-\alpha_m}}{(e^{\alpha_m}+a^{-\alpha_m})} (eαm+aαm)i=1Nwm,iI(yi=Gm(xi))eαmi=1Nwm,i=0i=1Nwm,ii=1Nwm,iI(yi=Gm(xi))=(eαm+aαm)eαm
可以看到上式左邊部分就是我們的當前第m輪模型的誤差率,所以令 e m = ∑ i = 1 N w m , i I ( y i ≠ G m ( x i ) ) ∑ i = 1 N w m , i e_m=\frac{\sum_{i=1}^Nw_{m,i}I(y_i\neq G_m(x_i))}{\sum_{i=1}^Nw_{m,i}} em=i=1Nwm,ii=1Nwm,iI(yi=Gm(xi)),這裡的e時誤差的意思,和上式右半部分的e的不同,然後將其帶入上式可得到:
α m = 1 2 l o g 1 − e m e m \alpha_m=\frac{1}{2}log\frac{1-e_m}{e_m} αm=21logem1em
然後結合 w m , i = e x p [ − y i f m − 1 ( x i ) ] w_{m,i}=exp[-y_if_{m-1}(x_i)] wm,i=exp[yifm1(xi)] f m ( x ) = f m − 1 ( x ) + α m G m ( x ) f_m(x)=f_{m-1}(x)+\alpha_mG_m(x) fm(x)=fm1(x)+αmGm(x)得出權值更新的公式:
f m ( x i ) = f m − 1 ( x i ) + α m G m ( x i ) ⇒ − y i f m ( x i ) = − y i f m − 1 ( x i ) − y i α m G m ( x i ) ⇒ e − y i f m ( x i ) = e − y i f m − 1 ( x i ) e − y i α m G m ( x i ) ⇒ w m + 1 , i = w m , i e − y i α m G m ( x i ) f_m(x_i)=f_{m-1}(x_i)+\alpha_mG_m(x_i)\\\Rarr -y_if_m(x_i)=-y_if_{m-1}(x_i)-y_i\alpha_mG_m(x_i)\\\Rarr e^{-y_if_m(x_i)}=e^{-y_if_{m-1}(x_i)}e^{-y_i\alpha_mG_m(x_i)}\\\Rarr w_{m+1,i}=w_{m,i}e^{-y_i\alpha_mG_m(x_i)} fm(xi)=fm1(xi)+αmGm(xi)yifm(xi)=yifm1(xi)yiαmGm(xi)eyifm(xi)=eyifm1(xi)eyiαmGm(xi)wm+1,i=wm,ieyiαmGm(xi)
然後對權值繼續規範化,使其之和為1,然後對應的誤差 e m e_m em中的分母也就為1。

1.5python實現

這裡實現的一個簡易版的,基學習器使用一個根節點的決策樹,資料集採用西瓜書對應章節的資料進行簡單測試。

import numpy as np
import pandas as pd
#構建單層決策樹為基分類器的提升模型
def load_data():
    df = pd.DataFrame()
    df['密度'] = [0.697, 0.774, 0.634, 0.608, 0.556, 0.403, 0.481, 0.437, 0.666, 0.243, 0.245, 0.343, 0.639, 0.657,
                0.360, 0.593, 0.719]
    df['含糖量'] = [0.460, 0.376, 0.264, 0.318, 0.215, 0.237, 0.149, 0.211, 0.091, 0.267, 0.057, 0.099, 0.161, 0.198,
                 0.370, 0.042, 0.103]
    df["好瓜"] = ["是", "是", "是", "是", "是", "是", "是", "是", "否", "否", "否", "否", "否", "否", "否", "否", "否"]
    df.to_csv('data/watermelon45.csv', index=0)

#計算更新樣本的權重
def cal_sample_weight(weight_list:[],y_true:[],y_pred:[],am):
    weight_list = np.array(weight_list)*np.exp(-am*(y_true*y_pred))
    Zm = np.sum(weight_list)
    return list(weight_list/Zm)

#計算第m輪模型的權重
def cal_tree_weight(em):
    return np.log((1 - em) / em) / 2

def cal_em(feat_value_list:[], threshold, y_true:[], weight_list:[], flag='l'):
    :param feat_value_list: 劃分特徵的所有取值
    :param threshold: 閾值
    :param y_true: 樣本的真實標籤列表
    :param weight_list: 樣本當前的權重
    :return: 誤差率

    y_pred = np.ones(len(y_true))
    if flag == 'l':
        y_pred[np.array(feat_value_list)>threshold] = -1 #大於閾值的預測為-1,小於閾值的預測為1
    elif flag == 'r':
        y_pred[np.array(feat_value_list) < threshold] = -1 #大於閾值的預測為1,小於閾值的預測為-1
    em = np.sum(np.array(weight_list)[y_pred != y_true])
    return em,y_pred

#構建單層決策樹
def build_stump(data:pd.DataFrame, weight_list:[], label:[]):

    :param data: 訓練資料
    :param weight_list: 訓練樣本的權重
    :param label: 資料的真實標籤
    :return:
    min_em = np.inf #找到使得當前權重下誤差率最小的分類器
    tree = {} #返回的單層決策樹
    best_feat = '' #最優劃分特徵
    best_threshold = -1 #最優劃分特徵下產生的最優化閾值
    ret_y_pred = [] #最優劃分下決策樹的預測結果
    best_flag = ''
    for feat in data.columns.values:
        feat_value_list = list(data[feat]) #該屬性下的取值
        sorted_feat_value_list = sorted(list(set(feat_value_list)))
        threshold_list = [(sorted_feat_value_list[i]+sorted_feat_value_list[i+1])/2 for i in np.arange(len(sorted_feat_value_list)-1)]
        for threshold in threshold_list:
            for flag in ['l','r']:
                cur_em, y_pred = cal_em(feat_value_list, threshold, label, weight_list, flag) #計算誤差率
                if cur_em < min_em:
                    min_em = cur_em
                    best_feat = feat
                    best_threshold = threshold
                    ret_y_pred = y_pred
                    best_flag = flag

    return best_feat, best_threshold, min_em, ret_y_pred, best_flag

#構建提升樹分類模型
def build_adaboost_classifier(data:pd.DataFrame, n=5):
    :param data: 訓練資料集
    :param n: 指定基分類器的數量
    :return: 返回整合分類器

    train_features = np.array(data.columns)[:-1]
    label_feature = np.array(data.columns)[-1]
    train_data = data[train_features]
    label = data[label_feature]
    weight_list = np.ones(len(label))/len(label) #初始化權重
    adaboost_clf = []
    for _ in np.arange(n):
        best_feat, best_threshold, min_em, y_pred,best_flag = build_stump(train_data, weight_list, label)
        am = cal_tree_weight(min_em)
        weight_list = cal_sample_weight(weight_list,label,y_pred,am)
        adaboost_clf.append((am,best_feat,best_threshold,best_flag))
        print(weight_list)
        print('誤差率:.{} 閾值:.{} flag:.{}'.format(min_em, best_threshold, best_flag))

    return adaboost_clf

#分類器預測
def predict(data:pd.DataFrame, clf_list:[]):
    y_pred = np.zeros(len(data))
    for (am,best_feat,best_threshold,best_flag) in clf_list:
        y_pred_tmp = np.ones(len(data))
        if best_flag == 'l':
            y_pred_tmp[data[best_feat]>best_threshold] = -1
        elif best_flag == 'r':
            y_pred_tmp[data[best_feat] < best_threshold] = -1

        y_pred += am*y_pred_tmp

    y_pred[y_pred>0] = 1
    y_pred[y_pred<=0] = -1

    return y_pred


if __name__ == '__main__':
    watermelon = pd.read_csv('data/watermelon45.csv')
    watermelon['好瓜'] = watermelon['好瓜'].map({'是':1,'否':-1})
    print(watermelon)
    # feat_value_list = [0,1,2,3,4,5,6,7,8,9]
    # df = pd.DataFrame(columns=['feat1','feat2'])
    # y_true = [1, 1, 1, -1, -1, -1, 1, 1, 1, -1]
    # df['feat1'] = feat_value_list
    # df['feat2'] = feat_value_list
    # df['label'] = y_true
    # weight_list = [0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1]

    # print(build_stump(df,weight_list,y_true))
    clf_list = build_adaboost_classifier(watermelon, n=11)
    y_pred = predict(watermelon, clf_list)
    print(list(watermelon['好瓜']))
    print(y_pred)
    print(np.sum(np.ones(len(y_pred))[y_pred!=list(watermelon['好瓜'])]))

2.AdaBoost迴歸

2.1基本思想

AdaBoost用於迴歸問題時也是採用前向分步演算法的思想,基函式使用迴歸樹 T ( x ) T(x) T(x)(迴歸樹的原理可以參考機器學習決策樹DecisionTree以及python程式碼實現),損失函式使用平方誤差損失 L ( y , f ( x ) ) = ( y − f ( x ) ) 2 L(y,f(x))=(y-f(x))^2 L(y,f(x))=(yf(x))2,根據前向分步演算法的思想,我們當前m輪的加法模型就是 f m ( x ) = f m − 1 ( x ) + T m ( x ) f_{m}(x)=f_{m-1}(x)+T_m(x) fm(x)=fm1(x)+Tm(x),假設我們已經經過m-1輪得到了 f m − 1 ( x ) f_{m-1}(x) fm1(x),那麼我們第m輪的優化目標就變成如下形式:
a r g m i n T m ∑ i = 1 N L ( y i , f m − 1 ( x i ) + T m ( x i ) ) 2 ⇒ a r g m i n T m ∑ i = 1 N ( y i − f m − 1 ( x i ) − T m ( x i ) ) 2 ⇒ a r g m i n T m ∑ i = 1 N ( r m , i − T m ( x i ) ) 2 argmin_{T_m}\sum_{i=1}^{N}L(y_i,f_{m-1}(x_i)+T_m(x_i))^2\\\Rarr argmin_{T_m}\sum_{i=1}^{N}(y_i-f_{m-1}(x_i)-T_m(x_i))^2\\\Rarr argmin_{T_m}\sum_{i=1}^{N}(r_{m,i}-T_m(x_i))^2 argminTmi=1NL(yi,fm1(xi)+Tm(xi))2argminTmi=1N(yifm1(xi)Tm(xi))2argminTmi=1N(rm,iTm(xi))2
其中, r m , i = y i − f m − 1 ( x i ) r_{m,i}=y_i-f_{m-1}(x_i) rm,i=yifm1(xi)表示當前模型的殘差(即當前模型預測值和真實值的差),所以第m輪的優化目標就變成去擬合當前模型 f m − 1 ( x ) f_{m-1}(x) fm1(x)的殘差,所以我們只需要每一輪使用一個迴歸樹去擬合殘差即可,最後將模型線性相加即可。

2.2演算法的具體步驟:

輸入:訓練資料集 T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x N , y N ) } T=\{(x_1,y_1),(x_2,y_2),...,(x_N,y_N)\} T={(x1,y1),(x2,y2),...,(xN,yN)} x ∈ R n , y ∈ R x\in R^n, y\in R xRn,yR
輸出:提升樹

  1. 初始化 f 0 ( x ) = 0 f_0(x)=0 f0(x)=0
  2. 對m=1,2,…,M。
    (1)計算殘差: r m , i = y i − f m − 1 ( x i ) , i = 1 , 2 , . . . , N r_{m,i}=y_i-f_{m-1}(x_i), i=1,2,...,N rm,i=yifm1(xi),i=1,2,...,N
    (2)通過擬合 r m , i r_{m,i} rm,i構建一個迴歸樹 T m ( x ) T_m(x) Tm(x)
    (3)更新: f m ( x ) = f m − 1 ( x ) + T m ( x ) f_m(x)=f_{m-1}(x)+T_{m}(x) fm(x)=fm1(x)+Tm(x)
  3. 得到迴歸提升樹: f M ( x ) = ∑ m = 1 M T m ( x ) f_M(x)=\sum_{m=1}^MT_m(x) fM(x)=m=1MTm(x)

2.3python實現

這裡我們呼叫的前面決策樹中實現的迴歸樹,來構建一個簡易版的提升樹。

import numpy as np
import pandas as pd
from DecisionTree import decisiontreeRegressor

'''構建迴歸樹為基模型的提升樹迴歸模型'''

def build_adaboost_regressor(data:pd.DataFrame, n=5):
    '''
    :param data: 訓練集
    :param n: 基分類器的數量,基模型預設使用max_depth=1的迴歸樹
    :return:
    '''
    adaboost_regressor = [] #整合模型
    train_data = data[np.array(data.columns)[:-1]]
    y_true = data[np.array(data.columns)[-1]]
    base_model = decisiontreeRegressor.build_regressionTree(train_data, y_true, cur_depth=1,max_depth=1)
    y_pred = decisiontreeRegressor.predict(base_model, train_data) #當前加法模型的預測結果
    adaboost_regressor.append(base_model)
    for _ in np.arange(n-1):
        r = y_true - y_pred #當前模型和真實值的殘差
        # print('mse:.{}'.format(np.sum(r**2)))
        base_model = decisiontreeRegressor.build_regressionTree(train_data, r, cur_depth=1, max_depth=1)
        r_pred = decisiontreeRegressor.predict(base_model, train_data)
        y_pred = y_pred + r_pred # 模型相加的預測結果
        adaboost_regressor.append(base_model)

    return adaboost_regressor

def predict(data:pd.DataFrame, model:[]):
    y_pred = np.zeros(len(data))
    for base_model in model:
        y_pred += decisiontreeRegressor.predict(base_model, data)

    return y_pred

if __name__ == '__main__':
    df = pd.DataFrame(columns=['x1'])
    df['x1'] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    y_true = [5.56, 5.70, 5.91, 6.40, 6.80, 7.05, 8.90, 8.70, 9.00, 9.05]
    df['y'] = y_true
    tree_list = build_adaboost_regressor(df, 6)
    for tree in tree_list:
        print(tree)

    y_pred = predict(df.loc[:,['x1']],tree_list)
    # print(np.sum((y_pred-y_true)**2)/len(y_pred))

相關文章