突破最强集成算法模型,Adaboost!!

文摘   2024-11-01 15:36   北京  

哈喽,我是cos大壮!~

今天和大家再聊聊Adaboost

关于集成学习、Adaboost算法本身、以及如果通透的理解其内在的原理,咱们今天一篇文章搞定~

我们可以把「集成算法」比喻成一个团队,目标是通过集体的力量来解决问题。在机器学习中,单个模型(比如一个小决策树)可能没法很好地解决问题,但如果我们把很多个小模型组合起来,就能取得更好的效果。这种把多个模型结合在一起的方法,就叫「集成算法」。

Adaboost 是一种「集成算法」,全名叫「Adaptive Boosting」,意思是「自适应增强」。Adaboost 有一个聪明的地方,就是会根据模型的表现去分配权重和关注点,努力让团队的整体能力越来越强。

老规矩如果大家伙觉得近期文章还不错!欢迎大家点个赞、转个发,文末赠送《机器学习学习小册》

文末可取本文PDF版本~


好了,下面咱们详细的聊聊Adaboost

工作原理

假设你是一位老师,想知道班上50个学生会不会通过考试。单靠你自己去预测每个人的成绩可能不准,所以你决定请几个同事帮忙预测。

第一步:建立第一个预测模型

你的第一位同事A来了。他根据以往经验对每个学生的通过与否做了一个预测,准确率是50%。虽然预测不太准,但他总归给了一些参考。

第二步:给出权重,专注错误

接下来,你发现有一些学生A预测错了。这时候,Adaboost会给这些被预测错的学生分配更高的权重,意思是让下一个预测者更关注这些学生。

第三步:建立第二个模型,改进错误

这次,你的第二位同事B来了。因为他知道哪些学生被前一个预测者弄错了,所以会格外关注这些学生。这次预测完后,整体准确率有了一些提升。

第四步:继续循环,不断改进

接下来Adaboost会继续找其他同事C、D、E等等,每个新来的同事都会更关注之前错误的地方,逐步提高准确率。每个人做完预测后,还会给出一个权重,准确预测多的权重大,错误多的权重小。

最终,Adaboost把所有同事的预测结果整合在一起。由于每个同事都专注于自己擅长的部分,而且一开始错误的地方也被逐步改进,整个团队的预测结果会比单个同事更准。

大家可以看到,Adaboost的核心就是「集体智慧」+「专注错误」。通过一轮轮提升,每次都让模型关注不同的重点地方,最终让整体的预测准确率越来越高。

总计一句话,Adaboost通过让一系列模型(团队成员)专注于前面的错误并不断改进,从而形成一个更强大的集成模型。这就像一个团队不断学习,最后做出比单个人更好的决策。

有了这个简单的案例,大家应该对Adaboost有了一个整体的印象了。下面,咱们通过详细的原理、公式推理介绍给大家,最后给出一个案例~

一点原理

Adaboost 的原理在于将多个弱学习器(例如简单的决策树)组合成一个强学习器。

核心思想是每个新加入的模型更专注于修正前一个模型的错误。

Adaboost 算法步骤

假设我们有一个数据集 ,其中  表示样本标签。我们希望通过多个弱分类器组合得到一个强分类器。

1. 初始化样本权重:将每个样本的权重初始化为 

2. 迭代训练弱分类器

对于每一轮 ,执行以下步骤:

  • 使用当前样本权重  训练弱分类器 ,输出预测结果。

  • 计算分类错误率 

其中  是一个指标函数,当分类错误时为1,否则为0。

  • 计算弱分类器的权重 

权重  越大表示该分类器的准确率越高。

  • 更新样本权重 ,使得分类错误的样本获得更高权重:

然后对权重  进行归一化,以确保权重之和为1。

3. 组合弱分类器:最终的分类结果为弱分类器的加权和:

完整案例

我们使用Kaggle上的Iris数据集来分类不同类型的鸢尾花。我们将代码从零开始实现Adaboost算法,包含数据预处理、模型训练和图形可视化。

数据获取:点击名片,回复「数据集」即可~

在代码中:

  1. Adaboost算法的实现。
  2. 使用决策边界、分类效果、样本权重分布等可视化图形来直观展示训练过程。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split

# 读取并处理数据集
data = pd.read_csv("Iris.csv")
data = data[data["Species"] != "Iris-virginica"]  # 选择两个分类,便于二分类
X = data[["SepalLengthCm""SepalWidthCm"]].values
y = np.where(data["Species"] == "Iris-setosa"-11)  # 将类别映射为-1和1

# 分割数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# Adaboost的基础实现
class WeakClassifier:
    def __init__(self):
        self.threshold = None
        self.feature_index = None
        self.polarity = 1
        
    def train(self, X, y, weights):
        n_samples, n_features = X.shape
        min_error = float('inf')
        
        # 尝试每个特征
        for feature_i in range(n_features):
            feature_values = X[:, feature_i]
            possible_thresholds = np.unique(feature_values)
            
            for threshold in possible_thresholds:
                for polarity in [1-1]:
                    predictions = np.ones(y.shape)
                    predictions[polarity * feature_values < polarity * threshold] = -1
                    
                    error = np.sum(weights[y != predictions])
                    
                    if error < min_error:
                        self.polarity = polarity
                        self.threshold = threshold
                        self.feature_index = feature_i
                        min_error = error
                        
    def predict(self, X):
        feature_values = X[:, self.feature_index]
        predictions = np.ones(X.shape[0])
        predictions[self.polarity * feature_values < self.polarity * self.threshold] = -1
        return predictions

class AdaBoost:
    def __init__(self, n_classifiers=10):
        self.n_classifiers = n_classifiers
        self.classifiers = []
        self.alphas = []
        self.errors = []
        self.sample_weights_history = []
        
    def train(self, X, y):
        n_samples, _ = X.shape
        weights = np.full(n_samples, 1 / n_samples)
        
        for _ in range(self.n_classifiers):
            classifier = WeakClassifier()
            classifier.train(X, y, weights)
            predictions = classifier.predict(X)
            
            error = np.dot(weights, predictions != y)
            alpha = 0.5 * np.log((1 - error) / (error + 1e-10))
            
            weights *= np.exp(-alpha * y * predictions)
            weights /= np.sum(weights)
            
            self.classifiers.append(classifier)
            self.alphas.append(alpha)
            self.errors.append(error)
            self.sample_weights_history.append(weights.copy())
        
    def predict(self, X):
        clf_preds = [alpha * clf.predict(X) for clf, alpha in zip(self.classifiers, self.alphas)]
        return np.sign(np.sum(clf_preds, axis=0))

# 训练模型
adaboost = AdaBoost(n_classifiers=10)
adaboost.train(X_train, y_train)

# 可视化1:决策边界
def plot_decision_boundary(X, y, model, ax):
    x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1), np.arange(y_min, y_max, 0.1))
    Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    ax.contourf(xx, yy, Z, alpha=0.3, cmap='coolwarm')
    ax.scatter(X[:, 0], X[:, 1], c=y, cmap='coolwarm', edgecolor='k', s=20)

fig, ax = plt.subplots(11, figsize=(106))
plot_decision_boundary(X_test, y_test, adaboost, ax)
ax.set_title("Adaboost Decision Boundary")
plt.show()

# 可视化2:样本权重变化图
plt.figure(figsize=(106))
for i, weights in enumerate(adaboost.sample_weights_history):
    plt.plot(range(1, len(weights) + 1), weights, label=f'Iteration {i + 1}')
plt.xlabel('Sample Index')
plt.ylabel('Sample Weight')
plt.title('Sample Weight Distribution Over Iterations')
plt.legend(loc='upper right')
plt.show()

# 可视化3:分类器权重变化图
plt.figure(figsize=(106))
plt.plot(range(1, len(adaboost.alphas) + 1), adaboost.alphas, marker='o', color='b')
plt.xlabel('Iteration')
plt.ylabel('Alpha (Classifier Weight)')
plt.title('Weak Classifier Weights (Alpha) Over Iterations')
plt.grid(True)
plt.show()

# 可视化4:模型误差随迭代次数变化图
plt.figure(figsize=(106))
plt.plot(range(1, len(adaboost.errors) + 1), adaboost.errors, marker='o', color='r')
plt.xlabel('Iteration')
plt.ylabel('Error Rate')
plt.title('Model Error Rate Over Iterations')
plt.grid(True)
plt.show()

1. 决策边界图:展示了模型在特征空间中的分类边界,用不同颜色表示模型的分类区域,帮助直观了解模型如何划分样本空间。

2. 样本权重分布图:显示了每一轮训练后样本的权重。随着迭代增加,错误分类的样本逐渐获得更高的权重,而容易分类的样本权重降低。这表明模型逐渐关注难以分类的样本。

3. 分类器权重变化图:展示每一轮弱分类器的权重。权重较高的分类器对最终决策影响更大;权重的波动反映了各个弱分类器的相对重要性。

4. 模型误差随迭代次数变化图:展示模型每轮的错误率。通常情况下,错误率会逐渐下降,表明模型在逐步提高对数据的拟合度。‘

这些数据分析图表提供了Adaboost训练过程中模型学习与调整的细节,有助于大家更深入地理解Adaboost的工作原理。

最后

大家有问题可以直接在评论区留言即可~

喜欢本文的朋友可收藏、点赞、转发起来!

需要本文PDF的同学,扫码备注「基础算法」即可~ 
关注本号,带来更多算法干货实例,提升工作学习效率!
最后,给大家准备了《机器学习学习小册》PDF版本16大块的内容,124个问题总结
100个超强算法模型,大家如果觉得有用,可以点击查看~

推荐阅读

原创、超强、精华合集
100个超强机器学习算法模型汇总
机器学习全路线
机器学习各个算法的优缺点
7大方面,30个最强数据集
6大部分,20 个机器学习算法全面汇总
铁汁,都到这了,别忘记点赞呀~

深夜努力写Python
Python、机器学习算法
 最新文章