从0开始实现一个Adaboost分类器(完整代码)

简介: 日前,通俗易懂的推导了三种集成学习的原理及主要公式,今天本文基于Python从0开始手动实现一个Adaboost分类器,文中提供完整代码。

640.jpg


01 Adaboost


基本原理回顾Adaboost作为一种提升集成算法,核心思想是不断训练弱学习器,来针对性的提升前一轮中预测错误样本的权重,最终通过加权所有弱学习器的训练结果得到最终分类标签。Adaboost是一种加权提升的集成算法,关键在于两个权重系数:

  • 弱学习器权重,影响每个弱学习器的结果对最终集成学习结果的影响程度,与该学习器的错误率有关
  • 样本权重,这也是Adaboost算法的精髓所在,即每轮训练弱学习器时不断优化调整样本间的权重,保证前一轮中学习错误的样本在下一轮训练中受到重点照顾


弱学习器的权重为:

微信截图_20220527165354.png

为学习器错误率


样本权重更新迭代公式为:


微信截图_20220527165406.png


具体含义及推导过程详见:三种集成学习算法原理及核心公式推导


值得指出,在sklearn库内置的Adaboost算法中,当解决分类问题时弱学习器选择最大深度为1的决策树(俗称决策树桩),解决回归问题时则选择最大深度为3的决策树(CART)。


02 决策树桩


本文以分类问题为例实现Adaboost算法,所以首先探索实现一个最大深度只有一层的决策树桩。


简单起见,假设样本为连续数值型特征,要实现一个最大深度只有一层决策树桩,那么实际上无论有多少个特征,也仅会用到其中一个特征作为分类。则问题等价于确定以下三个参数:

  • 确定选择哪一列特征作为分类依据
  • 选择的特征列中,以什么数值作为二分类的阈值
  • 特征与阈值的判别符号问题,即大于阈值还是小于阈值判断为正类


由于是分类问题,那么选择最优参数的依据不妨可以选择为Accuracy。当然,由于该决策树桩需要支持样本权重参数,所以这里的Accuracy严谨的说是指所有分类正确的样本权重之和占所有样本权重之和的比例,当执行样本权重归一化时所有样本权重之和为1。


基于此,一个简单的决策树桩实现思路就比较清晰了,实现3重循环依次遍历寻找最有参数组合即可。另外,沿袭sklearn标准库中的做法,这里仅实现fit()、predict()和score()三个核心接口。


详细代码如下,配合注解应该比较简单易懂:


class DecisionTreeClassifierWithWeight:
    def __init__(self):
        self.best_err = 1  # 最小的加权错误率
        self.best_fea_id = 0  # 最优特征id
        self.best_thres = 0  # 选定特征的最优阈值
        self.best_op = 1  # 阈值符号,其中 1: >, 0: <
    def fit(self, X, y, sample_weight=None):
        if sample_weight is None:
            sample_weight = np.ones(len(X)) / len(X)
        n = X.shape[1]
        for i in range(n):
            feature = X[:, i]  # 选定特征列
            fea_unique = np.sort(np.unique(feature))  # 将所有特征值从小到大排序
            for j in range(len(fea_unique)-1):
                thres = (fea_unique[j] + fea_unique[j+1]) / 2  # 逐一设定可能阈值
                for op in (0, 1):
                    y_ = 2*(feature >= thres)-1 if op==1 else 2*(feature < thres)-1  # 判断何种符号为最优
                    err = np.sum((y_ != y)*sample_weight)
                    if err < self.best_err:  # 当前参数组合可以获得更低错误率,更新最优参数
                        self.best_err = err
                        self.best_op = op
                        self.best_fea_id = i
                        self.best_thres = thres
        return self
    def predict(self, X):
        feature = X[:, self.best_fea_id]
        return 2*(feature >= self.best_thres)-1 if self.best_op==1 else 2*(feature < self.best_thres)-1
    def score(self, X, y, sample_weight=None):
        y_pre = self.predict(X)
        if sample_weight is not None:
            return np.sum((y_pre == y)*sample_weight)
        return np.mean(y_pre == y)


这里以sklearn库中自带的乳腺癌二分类数据集为例,以上述实现的决策树桩进行训练和评分,得到最终得分0.867,这对于一个仅有单层决策树的分类器来说效果还是比较好的。


from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
X, y = load_breast_cancer(return_X_y=True)
y = 2*y-1  # 将0/1取值映射为-1/1取值
X_train, X_test, y_train, y_test = train_test_split(X, y)
DecisionTreeClassifierWithWeight().fit(X_train, y_train).score(X_test, y_test)
# 0.8671328671328671


注:按照Adaboost中的算法约定,二分类模型中标签分别用-1和1代表负类和正类。


03 Adaboost集成分类器


在实现决策树桩作为弱分类器的基础上,实现Adaboost算法就仅需按照算法流程逐层训练即可。简单起见,这里仅设置超参数n_estimators用于选择弱分类器的个数。为区分于sklearn中的Adaboost标准内置库,本文将自定义实现的Adaboost分类算法命名为AdaBoostClassifier_,并设置相同的默认弱学习器数量超参数n_estimators=50,其余不做限制。


实质上,在逐渐调整样本权重的基础上,仅需逐层训练一个最优的决策树桩作为每轮的弱学习器,并保存在一个弱学习器列表中,同步记录每个弱学习器的权重系数。最后,在实现predict接口时,用每个弱学习器逐一完成训练,而后按其权重系数加权即可得到最终结果。完整代码如下:


class AdaBoostClassifier_:
    def __init__(self, n_estimators=50):
        self.n_estimators = n_estimators
        self.estimators = []
        self.alphas = []
    def fit(self, X, y):
        sample_weight = np.ones(len(X)) / len(X)  # 初始化样本权重为 1/N
        for _ in range(self.n_estimators):
            dtc = DecisionTreeClassifierWithWeight().fit(X, y, sample_weight)  # 训练弱学习器
            alpha = 1/2 * np.log((1-dtc.best_err)/dtc.best_err)  # 权重系数
            y_pred = dtc.predict(X)
            sample_weight *= np.exp(-alpha*y_pred*y)  # 更新迭代样本权重
            sample_weight /= np.sum(sample_weight)  # 样本权重归一化
            self.estimators.append(dtc)
            self.alphas.append(alpha)
        return self
    def predict(self, X):
        y_pred = np.empty((len(X), self.n_estimators))  # 预测结果二维数组,其中每一列代表一个弱学习器的预测结果
        for i in range(self.n_estimators):
            y_pred[:, i] = self.estimators[i].predict(X)
        y_pred = y_pred * np.array(self.alphas)  # 将预测结果与训练权重乘积作为集成预测结果
        return 2*(np.sum(y_pred, axis=1)>0)-1  # 以0为阈值,判断并映射为-1和1
    def score(self, X, y):
        y_pred = self.predict(X)
        return np.mean(y_pred==y)


最后,继续以乳腺癌二分类数据集为例,对比测试自定义实现的AdaBoostClassifier_算法与sklearn标准库中的AdaBoostClassifer算法性能,得到如下结果:


from sklearn.ensemble import AdaBoostClassifier
AdaBoostClassifier_().fit(X_train, y_train).score(X_test, y_test)
# 0.986013986013986
AdaBoostClassifier().fit(X_train, y_train).score(X_test, y_test)
# 0.965034965034965


除了训练效率略低,自定义实现Adaboost算法效果简直好的不得了。


本文按部就班的实现了一个Adaboost分类算法的baseline,实现了较好的分类效果,但仍有很多需要优化的点,例如对回归算法的支持、更多集成学习参数的设置以及特殊训练情况下的处理等。To be continued……


640.png


目录
相关文章
|
5月前
|
机器学习/深度学习 存储
集成学习方法——随机森林
之前我们介绍过决策树,随机森林(Random Forest)是将多个决策树(Decision Tree)组合在一起形成一个强大的分类器或回归器,是一种集成学习(Ensemble Learning)方法。 随机森林的主要思想是通过随机选择样本和特征来构建多个决策树,并通过集成这些决策树的预测结果来达到更准确的分类或回归结果。具体步骤如下: 随机选择部分训练样本集; 随机选择部分特征子集; 构建决策树,对每个节点进行特征选择和分裂; 再进行重复,构建多个决策树; 对每个决策树,根据投票或平均值等方法,获得最后的分类或回归结果。
|
15天前
|
数据可视化 Python
Python进行多输出(多因变量)回归:集成学习梯度提升决策树GRADIENT BOOSTING,GBR回归训练和预测可视化
Python进行多输出(多因变量)回归:集成学习梯度提升决策树GRADIENT BOOSTING,GBR回归训练和预测可视化
22 0
Python进行多输出(多因变量)回归:集成学习梯度提升决策树GRADIENT BOOSTING,GBR回归训练和预测可视化
|
16天前
|
机器学习/深度学习 算法 数据可视化
样条曲线、决策树、Adaboost、梯度提升(GBM)算法进行回归、分类和动态可视化
样条曲线、决策树、Adaboost、梯度提升(GBM)算法进行回归、分类和动态可视化
14 0
|
17天前
|
机器学习/深度学习 算法 数据可视化
R语言样条曲线、决策树、Adaboost、梯度提升(GBM)算法进行回归、分类和动态可视化
R语言样条曲线、决策树、Adaboost、梯度提升(GBM)算法进行回归、分类和动态可视化
12 0
|
10月前
特征选择:回归,二分类,多分类特征选择有这么多差异需要注意
特征选择:回归,二分类,多分类特征选择有这么多差异需要注意
99 0
|
12月前
|
机器学习/深度学习 算法
连载|GBDT如何进行回归和分类
连载|GBDT如何进行回归和分类
|
12月前
|
移动开发 算法
|
机器学习/深度学习 Python
神经网络中的损失函数正则化和 Dropout 并手写代码实现
神经网络中的损失函数正则化和 Dropout 并手写代码实现
132 0
神经网络中的损失函数正则化和 Dropout 并手写代码实现
|
机器学习/深度学习 算法 前端开发
集成学习方法之随机森林
集成学习通过建立几个模型组合的来解决单一预测问题。它的工作原理是生成多个分类器模型,各自独立地学习和作出预测。这些预测最后结合成组合预测,因此优于任何一个单分类的做出预测。
103 0
集成学习方法之随机森林
|
机器学习/深度学习 搜索推荐 算法
决策树算法之 AdaBoost
AdaBoost 是一种更高级的「森林」类型的决策树,和随机森林比起来,它有以下三个特点 1. AdaBoost 的每棵树都只有一个根节点和两个叶子节点,实际上叫树桩(stump)可能会更合适 2. AdaBoost 的每个树桩的权重是不同的,而随机森林中的每棵树的权重是相同的 3. 前一个树桩的错误数据会影响后一个树桩的生成,意味着后面的树桩是前面树桩的补足。这种思想也被称为 Boos