Adaboost,一个神奇算法模型 !!

文摘   2024-11-20 14:37   北京  

大家好~

今儿分享的是Adaboost,从前面的解释、理论部分,都后面咱们通过理论手撸代码,一起来学习一下~

什么是 Adaboost?

Adaboost 是一种机器学习的集成方法,全称是 "Adaptive Boosting"(自适应提升)。它属于一种「提升(Boosting)算法」,通过把很多弱的学习器组合起来,变成一个强大的学习器。这就像你问了一群普通人问题,虽然每个人的答案可能不完美,但通过一种聪明的方式结合他们的答案,最终得到一个非常好的答案。

什么是「弱学习器」?

弱学习器是指那些表现不太好但稍微好过随机猜测的模型。举个例子,假如你让一个弱学习器去判断今天是否会下雨,它可能只能比瞎猜稍微强一点,比如 55% 的正确率。

Adaboost 的神奇之处就在于,它能从这些弱学习器里,逐步提升整体的准确率,让它们的组合成为一个强学习器,最后的表现非常好!

Adaboost 的工作原理

  1. 开始时每个样本的权重相同:一开始,Adaboost 给数据集里的每个样本分配一个相等的权重。比如你有 10 个样本,每个样本的权重就是 

  2. 训练第一个弱学习器:我们用当前数据集去训练第一个弱学习器。它可能会对一些样本预测错误,但没关系。

  3. 给预测错误的样本更高的权重:然后,Adaboost 会给那些被第一个弱学习器预测错误的样本更高的权重。为什么要这样做?因为它希望下一个弱学习器特别关注这些难以预测的样本

  4. 训练下一个弱学习器:接着,我们用调整后的样本权重再训练一个新的弱学习器,这个学习器会对那些被上一个学习器错分的样本更敏感。

  5. 重复过程:这个过程会重复多次,每次都强调那些被前面弱学习器错分的样本,直到我们有足够多的弱学习器。

  6. 组合弱学习器的结果:最后,Adaboost 会把所有弱学习器的结果综合起来。每个学习器的投票权重是根据它的表现来分配的,表现好的弱学习器权重更高,表现差的权重更低。

简单的例子:

假设你想用 Adaboost 来判断一个水果是不是苹果,你现在有三个「弱学习器」:

  • 学习器1: 只看颜色(红色就猜是苹果),但有些红色水果是番茄,它可能出错;
  • 学习器2: 只看形状(圆形就猜是苹果),但有些圆形水果是橙子,它可能出错;
  • 学习器3: 只看大小(大小像苹果就猜是苹果),但梨子也有类似大小,它可能出错。

单独看这些学习器,它们都不太靠谱,因为每个都会犯一些错误。但是 Adaboost 会首先让每个弱学习器去做一次判断,比如:

  • 第一个学习器说:红色的水果是苹果,但错把红番茄也判断为苹果。
  • 第二个学习器说:圆形的水果是苹果,但错把橙子也判断为苹果。
  • 第三个学习器说:看大小,结果错把一个梨子当成苹果了。

这些学习器单独看可能不怎么样,但是 Adaboost 通过聪明的加权组合这些学习器的结果,最终得出一个更准确的判断。比如,它可能发现「如果颜色是红色、形状是圆形而且大小合适」那大概率就是苹果。所以最终结果比单独依赖一个学习器的预测要好得多。

好了,下面,我们详细推导 Adaboost 的公式,之后使用这些公式构建一个完整的案例。

1. Adaboost 算法的公式推导

初始条件

给定一个训练集 ,其中  是特征,  是标签。我们希望通过一系列弱分类器的组合来提高分类效果。

步骤 1:初始化权重

首先,我们初始化样本的权重分布 ,每个样本的权重相等,定义为:

其中  是样本数量。

步骤 2:训练弱分类器

在每一轮迭代  中,我们使用当前的权重分布  训练一个弱分类器 。它的误差率  定义为:

其中  是指示函数,当  时,值为 1,否则为 0。

步骤 3:计算分类器权重

对于第  个弱分类器,计算它的权重 ,公式如下:

这个权重  表示该弱分类器的影响力,错误率越低的分类器,其权重越高。

步骤 4:更新样本权重

接下来,更新样本的权重分布,以便下一个分类器更加关注那些被错误分类的样本。权重更新公式为:

然后进行归一化处理:

步骤 5:组合弱分类器

最终的分类结果是每个弱分类器的加权组合,公式为:

其中  是弱分类器的数量。

2. Python 实现 Adaboost

我们将使用自定义的 Adaboost 实现,并生成虚拟数据来进行分类。我们会在每轮迭代中输出相关图形。

代码实现

import numpy as np
import matplotlib.pyplot as plt

# 生成虚拟数据集
def generate_data(n):
    np.random.seed(10)
    X = np.random.randn(n, 2)  # 两个特征
    y = 2 * (X[:, 0] * X[:, 1] > 0) - 1  # 类别标签,取-1或1
    return X, y

# 定义弱分类器(基于单个特征阈值)
def weak_classifier(X, y, weights):
    m, n = X.shape
    min_error = float('inf')
    best_stump = None
    
    for feature in range(n):  # 遍历每个特征
        feature_values = X[:, feature]
        thresholds = np.unique(feature_values)  # 使用唯一值作为阈值
        
        for threshold in thresholds:
            for polarity in [1-1]:  # 正方向或反方向的阈值
                pred = np.ones(m)
                pred[polarity * feature_values < polarity * threshold] = -1
                
                error = sum(weights[y != pred])  # 计算加权错误率
                if error < min_error:
                    min_error = error
                    best_stump = {
                        'feature': feature,
                        'threshold': threshold,
                        'polarity': polarity,
                        'error': error,
                        'pred': pred
                    }
    
    return best_stump

# Adaboost 实现
def adaboost(X, y, T):
    m, n = X.shape
    weights = np.ones(m) / m  # 初始化权重
    alphas = []
    classifiers = []
    
    for t in range(T):
        stump = weak_classifier(X, y, weights)  # 训练弱分类器
        error = stump['error']
        
        # 计算弱分类器的权重
        alpha = 0.5 * np.log((1 - error) / (error + 1e-10))
        alphas.append(alpha)
        classifiers.append(stump)
        
        # 更新样本权重
        weights = weights * np.exp(-alpha * y * stump['pred'])
        weights = weights / np.sum(weights)  # 归一化
        
        # 可视化样本权重变化
        plot_sample_weights(X, y, weights, t)
    
    return alphas, classifiers

# 可视化样本权重
def plot_sample_weights(X, y, weights, iteration):
    plt.figure(figsize=(66))
    colors = ['r' if label == 1 else 'b' for label in y]
    plt.scatter(X[:, 0], X[:, 1], s=weights * 1000, c=colors, alpha=0.6, edgecolor='k')
    plt.title(f'Iteration {iteration + 1} - Sample Weights')
    plt.xlabel('Feature 1')
    plt.ylabel('Feature 2')
    plt.show()

# 最终分类器的决策边界
def plot_decision_boundary(X, y, classifiers, alphas):
    xx, yy = np.meshgrid(np.linspace(X[:, 0].min() - 1, X[:, 0].max() + 1100),
                         np.linspace(X[:, 1].min() - 1, X[:, 1].max() + 1100))
    grid = np.c_[xx.ravel(), yy.ravel()]
    
    final_pred = np.zeros(grid.shape[0])
    for alpha, clf in zip(alphas, classifiers):
        feature, threshold, polarity = clf['feature'], clf['threshold'], clf['polarity']
        preds = np.ones(grid.shape[0])
        preds[polarity * grid[:, feature] < polarity * threshold] = -1
        final_pred += alpha * preds
    
    final_pred = np.sign(final_pred)
    final_pred = final_pred.reshape(xx.shape)
    
    plt.figure(figsize=(66))
    plt.contourf(xx, yy, final_pred, alpha=0.3, cmap='coolwarm')
    plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='coolwarm', edgecolors='k')
    plt.title('Final Decision Boundary')
    plt.xlabel('Feature 1')
    plt.ylabel('Feature 2')
    plt.show()

# 生成数据并训练模型
X, y = generate_data(100)
T = 10  # 迭代次数
alphas, classifiers = adaboost(X, y, T)

# 可视化最终决策边界
plot_decision_boundary(X, y, classifiers, alphas)

样本权重变化图:每次迭代后,样本权重都会变化。这些图展示了每轮迭代中,哪些样本权重增加(被错分的样本权重增大)。

最终决策边界图:展示了经过多轮 Adaboost 迭代后,组合多个弱分类器的最终分类决策边界。

数据点和决策边界对比明显,希望能够很好地帮助理解 Adaboost 的工作原理。

最后

最近准备了16大块的内容,124个算法问题的总结,完整的机器学习小册,免费领取~

另外,今天给大家准备了关于「深度学习」的论文合集,往期核心论文汇总,分享给大家。

点击名片,回复「深度学习论文」即可~

如果你对类似于这样的文章感兴趣。

欢迎关注、点赞、转发~

机器学习和人工智能AI
让我们一起期待 AI 带给我们的每一场变革!推送最新行业内最新最前沿人工智能技术!
 最新文章