大家好,我是小白~
今儿的基础算法,我们来聊AdaBoost~
首先,咱们来通俗易懂的聊聊 AdaBoost 是什么,能干什么?~
AdaBoost 是一种 提升方法,全称叫 Adaptive Boosting,翻译成中文就是自适应增强。它是一种用来组合多个弱分类器的算法,最后让它们变得更强大。这里的 “弱分类器” 是指那些表现不太好的模型,单独使用时准确率不高,但通过 AdaBoost 的技巧把它们结合在一起,能得到一个强大的分类器。
那么,AdaBoost 是怎么工作的呢?
开始的时候,我们有一个数据集,AdaBoost 会先训练一个简单的分类器(也就是“弱分类器”)。这个弱分类器在某些样本上做对了,但在其他样本上犯错了。
接下来,AdaBoost 会关注这些被第一个分类器错分的样本,给它们更高的权重,意思是让后面的分类器更加注意这些错误的地方。
然后,继续训练下一个分类器,这个新的分类器会尽量改进前一个分类器做错的地方。再次犯错的样本,权重又会进一步增大,直到最后为止。
最终,AdaBoost 会把所有这些弱分类器的结果组合起来,得到一个更强的分类器。这个组合过程也很聪明:表现好的分类器权重大,表现不好的分类器权重小。
用例子来解释
假设大家是老师,班里有三个同学负责给出考试及格不及格的判断。他们分别是小红、小明和小李。每个人的准确率都不是很高,他们单独判断的准确率只有 60%。现在,你想通过 AdaBoost 的方式,让他们一起做出更准确的判断。
第一步:初始化权重
你首先假设班里的所有同学的意见都一样重要。所以一开始每个同学的投票权重是一样的(比如每个人 1 票)。这时你让第一个同学小红判断一组学生是否及格。
小红可能在 60% 的学生上判断对了,但她也在 40% 的学生上判断错了。AdaBoost 发现小红对某些学生判断错了,那就要在下一轮里给这些学生更高的权重。
第二步:更新权重
接着,轮到第二个同学小明来判断了。因为 AdaBoost 注意到小红之前犯错的那些学生,它会让小明更加注意这些学生——这意味着在给小明的训练数据中,那些小红判断错误的学生占更大的比重。小明会尽量改进小红的错误。
第三步:再次更新
小明也不会百分之百准确,他也会犯错。所以第三轮的时候,你把小李拉过来,让他在小红和小明都搞错的地方下更多功夫。
最终结果:组合
最后,你不再单独听小红、小明或小李任何一个人的意见,而是结合他们三个人的判断。因为 AdaBoost 给每个人分配了不同的权重,表现好的同学(比如在关键学生上判断对了的)会有更多话语权,表现不好的同学权重就小。
通过这样的一轮轮调整,AdaBoost 最终会生成一个综合的“老师”,它能比任何单独的小红、小明或小李表现得都好。
总的来说,AdaBoost 的核心思想就是把多个表现一般的弱分类器(比如小红、小明、小李)组合起来,并且让每个后续分类器特别关注前面分类器做错的地方。最后,经过多轮的组合,得到一个强大的分类器,可以比单个分类器做得更好。
下面,咱们聊聊对应的原理、公式和一个完整的案例。
1. AdaBoost 算法公式推导
基本思想
假设我们有一个数据集 ,其中 是样本的特征, 是样本的标签。AdaBoost 的目标是通过加权组合一系列弱分类器来创建一个强分类器。
1. 弱分类器的训练: AdaBoost 会生成一系列弱分类器,每个弱分类器根据当前的样本权重进行训练。样本的权重表示这个样本的重要性。
2. 加权分类器的组合: AdaBoost 最终生成的分类器是多个弱分类器的加权和。我们给每个弱分类器一个权重,表现越好的分类器权重越大。
算法步骤
初始化样本权重:
给定样本 ,初始时,每个样本的权重都相等,初始化为:
循环 T 轮,训练弱分类器:
第 t 轮中:
1. 训练弱分类器:
使用当前的样本权重 训练一个弱分类器 。
2. 计算分类误差:
弱分类器在当前权重下的分类误差为:
其中 表示分类错误的样本。
3. 计算分类器权重:
分类器的权重表示其重要性,计算公式为:
4. 更新样本权重:
下一轮的样本权重更新为:
然后进行归一化,使得权重和为 1。
最终分类器:
最终的强分类器是所有弱分类器的加权和:
2. Python 案例
import numpy as np
import matplotlib.pyplot as plt
# 生成虚拟数据集
np.random.seed(42)
X = np.random.randn(1000, 2)
y = np.where(X[:, 0] + X[:, 1] > 0, 1, -1)
# 弱分类器:单层决策树 (简单的阈值分类器)
def weak_classifier(X, feature_index, threshold, polarity):
predictions = np.ones(X.shape[0])
if polarity == 1:
predictions[X[:, feature_index] < threshold] = -1
else:
predictions[X[:, feature_index] >= threshold] = -1
return predictions
# 训练一个弱分类器
def train_weak_classifier(X, y, weights):
n_samples, n_features = X.shape
best_classifier = {}
best_error = float('inf')
for feature_index in range(n_features):
feature_values = np.sort(X[:, feature_index])
for threshold in feature_values:
for polarity in [1, -1]:
predictions = weak_classifier(X, feature_index, threshold, polarity)
error = np.sum(weights * (predictions != y))
if error < best_error:
best_error = error
best_classifier = {
'feature_index': feature_index,
'threshold': threshold,
'polarity': polarity,
'predictions': predictions
}
return best_classifier, best_error
# AdaBoost 主流程
def adaboost(X, y, T=10):
n_samples = X.shape[0]
weights = np.ones(n_samples) / n_samples
classifiers = []
classifier_weights = []
for t in range(T):
classifier, error = train_weak_classifier(X, y, weights)
alpha = 0.5 * np.log((1 - error) / (error + 1e-10)) # 避免除以 0
classifiers.append(classifier)
classifier_weights.append(alpha)
# 更新权重
weights *= np.exp(-alpha * y * classifier['predictions'])
weights /= np.sum(weights) # 归一化
return classifiers, classifier_weights
# 预测函数
def predict(X, classifiers, classifier_weights):
n_samples = X.shape[0]
final_predictions = np.zeros(n_samples)
for classifier, alpha in zip(classifiers, classifier_weights):
predictions = weak_classifier(X, classifier['feature_index'],
classifier['threshold'],
classifier['polarity'])
final_predictions += alpha * predictions
return np.sign(final_predictions)
# 训练 AdaBoost 模型
T = 10 # 弱分类器数量
classifiers, classifier_weights = adaboost(X, y, T)
# 预测
y_pred = predict(X, classifiers, classifier_weights)
# 可视化
plt.figure(figsize=(12, 8))
# 图 1: 数据点分布
plt.subplot(2, 2, 1)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap='coolwarm', s=50)
plt.title('Data Distribution')
# 图 2: 弱分类器权重分布
plt.subplot(2, 2, 2)
plt.bar(range(1, T+1), classifier_weights, color='lightcoral')
plt.title('Classifier Weights')
# 图 3: 样本权重分布
plt.subplot(2, 2, 3)
weights_final = np.ones(X.shape[0]) / X.shape[0]
for classifier, alpha in zip(classifiers, classifier_weights):
weights_final *= np.exp(-alpha * y * classifier['predictions'])
weights_final /= np.sum(weights_final)
plt.bar(range(X.shape[0]), weights_final, color='seagreen')
plt.title('Sample Weights')
# 图 4: 分类结果
plt.subplot(2, 2, 4)
plt.scatter(X[:, 0], X[:, 1], c=y_pred, cmap='coolwarm', s=50)
plt.title('Predicted Classes')
plt.tight_layout()
plt.show()
图 1:数据点分布
展示了虚拟数据集的分布,红色和蓝色表示不同的类别。
图 2:弱分类器权重分布
每一轮的弱分类器都有一个权重,权重越高表示分类器在这轮中的表现越好。
图 3:样本权重分布
展示了经过多轮迭代后,样本的权重分布。错误分类的样本会获得更大的权重。
图 4:分类结果
最终的分类结果,展示了 AdaBoost 组合多个弱分类器后给出的预测。
最后
整个原理,以及代码手动实现了 AdaBoost 算法,并生成了多个图像,希望帮助到大家理解数据和分类过程中的权重变化。