集成学习(1)AdaBoost分别应用于分类和回归及其python实现


前言:近期在做比赛的时候建模阶段普遍都是使用集成模型效果更好,如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 ∑ y i = G m ( x i ) w m , i e − α m + ∑ y i ≠ G m ( x i ) w m , i e − α 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}\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}-\sum_{y_i\neq 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,Gmyi=Gm(xi)wm,ieαm+yi=Gm(xi)wm,ieαmyi=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))
  • 3
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Adaboost算法是一种集成学习算法,它能够将多个弱分类器组合成一个强分类器。其中,每个弱分类器的训练都是基于一个加权的数据集进行的。在每次迭代中,Adaboost算法会根据前一次的分类结果来调整每个样本的权重,以使得分类错误的样本受到更多的关注。这样,新的弱分类器就能够更加关注分类错误的样本,从而提高整体的分类性能。 逻辑斯蒂回归是一种二分类模型,它基于逻辑斯蒂函数来对样本进行分类。在训练过程中,我们需要最大化对数似然函数,从而求得模型的参数。对于每个样本,我们需要计算其梯度,然后根据梯度来更新模型的参数。 现在,我们可以将Adaboost算法中的权重更新方法用到逻辑斯蒂回归中。具体来说,我们可以将每个样本的权重视为Adaboost算法中的样本权重,然后使用梯度下降来更新模型参数。具体的实现如下: ```python import numpy as np class AdaboostLR: def __init__(self, n_estimators=50, learning_rate=1.0): self.n_estimators = n_estimators self.learning_rate = learning_rate self.estimators = [] def fit(self, X, y): # 初始化样本权重 w = np.ones(X.shape[0]) / X.shape[0] for i in range(self.n_estimators): # 训练一个逻辑斯蒂回归模型 estimator = LogisticRegression() estimator.fit(X, y, sample_weight=w) # 计算分类错误率 y_pred = estimator.predict(X) error_rate = np.sum(w * (y_pred != y)) / np.sum(w) # 计算模型权重 alpha = self.learning_rate * np.log((1 - error_rate) / error_rate) # 更新样本权重 w *= np.exp(alpha * (y_pred != y)) w /= np.sum(w) # 保存模型和权重 self.estimators.append((estimator, alpha)) def predict(self, X): # 预测结果为加权的所有弱分类器的预测结果之和 y_pred = np.zeros(X.shape[0]) for estimator, alpha in self.estimators: y_pred += alpha * estimator.predict(X) return np.sign(y_pred) ``` 在这个实现中,我们首先使用np.ones()函数初始化样本权重。然后,我们在每个迭代中训练一个逻辑斯蒂回归模型,并根据其预测结果来计算分类错误率。接下来,我们使用错误率计算模型权重,并使用权重更新样本权重。最后,我们保存模型和权重,并在预测时使用它们来计算加权的预测结果。 注意,这个实现中我们并没有使用sklearn中的AdaBoostClassifier类,而是手动实现Adaboost算法。这样做的好处是可以更好地理解Adaboost算法的原理。但是,使用sklearn中的AdaBoostClassifier类可以更方便地调整参数和处理数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值