哈喽,我是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算法,包含数据预处理、模型训练和图形可视化。
数据获取:点击名片,回复「数据集」即可~
在代码中:
Adaboost算法的实现。 使用决策边界、分类效果、样本权重分布等可视化图形来直观展示训练过程。
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", -1, 1) # 将类别映射为-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(1, 1, figsize=(10, 6))
plot_decision_boundary(X_test, y_test, adaboost, ax)
ax.set_title("Adaboost Decision Boundary")
plt.show()
# 可视化2:样本权重变化图
plt.figure(figsize=(10, 6))
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=(10, 6))
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=(10, 6))
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的工作原理。
最后
大家有问题可以直接在评论区留言即可~
喜欢本文的朋友可以收藏、点赞、转发起来!
推荐阅读
原创、超强、精华合集 100个超强机器学习算法模型汇总 机器学习全路线 机器学习各个算法的优缺点 7大方面,30个最强数据集 6大部分,20 个机器学习算法全面汇总 铁汁,都到这了,别忘记点赞呀~