大家好~
今儿分享的是Adaboost,从前面的解释、理论部分,都后面咱们通过理论手撸代码,一起来学习一下~
什么是 Adaboost?
Adaboost 是一种机器学习的集成方法,全称是 "Adaptive Boosting"(自适应提升)。它属于一种「提升(Boosting)算法」,通过把很多弱的学习器组合起来,变成一个强大的学习器。这就像你问了一群普通人问题,虽然每个人的答案可能不完美,但通过一种聪明的方式结合他们的答案,最终得到一个非常好的答案。
什么是「弱学习器」?
弱学习器是指那些表现不太好但稍微好过随机猜测的模型。举个例子,假如你让一个弱学习器去判断今天是否会下雨,它可能只能比瞎猜稍微强一点,比如 55% 的正确率。
Adaboost 的神奇之处就在于,它能从这些弱学习器里,逐步提升整体的准确率,让它们的组合成为一个强学习器,最后的表现非常好!
Adaboost 的工作原理
开始时每个样本的权重相同:一开始,Adaboost 给数据集里的每个样本分配一个相等的权重。比如你有 10 个样本,每个样本的权重就是 。
训练第一个弱学习器:我们用当前数据集去训练第一个弱学习器。它可能会对一些样本预测错误,但没关系。
给预测错误的样本更高的权重:然后,Adaboost 会给那些被第一个弱学习器预测错误的样本更高的权重。为什么要这样做?因为它希望下一个弱学习器特别关注这些难以预测的样本。
训练下一个弱学习器:接着,我们用调整后的样本权重再训练一个新的弱学习器,这个学习器会对那些被上一个学习器错分的样本更敏感。
重复过程:这个过程会重复多次,每次都强调那些被前面弱学习器错分的样本,直到我们有足够多的弱学习器。
组合弱学习器的结果:最后,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=(6, 6))
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() + 1, 100),
np.linspace(X[:, 1].min() - 1, X[:, 1].max() + 1, 100))
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=(6, 6))
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个算法问题的总结,完整的机器学习小册,免费领取~
另外,今天给大家准备了关于「深度学习」的论文合集,往期核心论文汇总,分享给大家。
点击名片,回复「深度学习论文」即可~
如果你对类似于这样的文章感兴趣。
欢迎关注、点赞、转发~