### 定义AdaBoost算法类
class Adaboost:
# 弱分类器个数
def __init__(self, n_estimators=5):
self.n_estimators = n_estimators
# Adaboost拟合算法
def fit(self, X, y):
m, n = X.shape
# (1) 初始化权重分布为均匀分布 1/N
w = np.full(m, (1/m))
# 处初始化基分类器列表
self.estimators = []
# (2) for m in (1,2,...,M)
for _ in range(self.n_estimators):
# (2.a) 训练一个弱分类器:决策树桩
estimator = DecisionStump()
# 设定一个最小化误差
min_error = float('inf')
# 遍历数据集特征,根据最小分类误差率选择最优划分特征
for i in range(n):
# 获取特征值
values = np.expand_dims(X[:, i], axis=1)
# 特征取值去重
unique_values = np.unique(values)
# 尝试将每一个特征值作为分类阈值
for threshold in unique_values:
p = 1
# 初始化所有预测值为1
pred = np.ones(np.shape(y))
# 小于分类阈值的预测值为-1
pred[X[:, i] < threshold] = -1
# 2.b 计算误差率
error = sum(w[y != pred])
# 如果分类误差大于0.5,则进行正负预测翻转
# 例如 error = 0.6 => (1 - error) = 0.4
if error > 0.5:
error = 1 - error
p = -1
# 一旦获得最小误差则保存相关参数配置
if error < min_error:
estimator.label = p
estimator.threshold = threshold
estimator.feature_index = i
min_error = error
# 2.c 计算基分类器的权重
estimator.alpha = 0.5 * np.log((1.0 - min_error) / (min_error + 1e-9))
# 初始化所有预测值为1
preds = np.ones(np.shape(y))
# 获取所有小于阈值的负类索引
negative_idx = (estimator.label * X[:, estimator.feature_index] < estimator.label * estimator.threshold)
# 将负类设为 '-1'
preds[negative_idx] = -1
# 2.d 更新样本权重
w *= np.exp(-estimator.alpha * y * preds)
w /= np.sum(w)
# 保存该弱分类器
self.estimators.append(estimator)
# 定义预测函数
def predict(self, X):
m = len(X)
y_pred = np.zeros((m, 1))
# 计算每个弱分类器的预测值
for estimator in self.estimators:
# 初始化所有预测值为1
predictions = np.ones(np.shape(y_pred))
# 获取所有小于阈值的负类索引
negative_idx = (estimator.label * X[:, estimator.feature_index] < estimator.label * estimator.threshold)
# 将负类设为 '-1'
predictions[negative_idx] = -1
# 2.e 对每个弱分类器的预测结果进行加权
y_pred += estimator.alpha * predictions
# 返回最终预测结果
y_pred = np.sign(y_pred).flatten()
return y_pred
代码实现了一个 Adaboost
类,用于训练和预测分类任务中的数据。实现方式完全按照文章《AdaBoost基本原理》中的所述步骤。
1. 类定义与初始化
class Adaboost:
def __init__(self, n_estimators=5):
self.n_estimators = n_estimators
这里定义了 Adaboost
类,并且在初始化方法 __init__
中定义了弱分类器的数量,即 n_estimators
,默认为 5。这意味着 AdaBoost 会使用 5 个弱分类器进行训练。
2. 拟合方法 fit
fit
方法用于训练 AdaBoost 模型:
def fit(self, X, y):
m, n = X.shape
w = np.full(m, (1/m))
self.estimators = []
-
初始化样本权重
w
为均匀分布 1 m \frac{1}{m} m1。 -
初始化基分类器列表
self.estimators
,用来保存每一轮训练的弱分类器。
主循环:对每个弱分类器进行训练
for _ in range(self.n_estimators):
estimator = DecisionStump()
min_error = float('inf')
循环 self.n_estimators
次,每次训练一个弱分类器。在每一轮中:
-
estimator
表示一个弱分类器,这里假设定义了DecisionStump
类用于构建决策树桩。 -
min_error
用于记录当前轮次中的最小分类误差,初始值设为无穷大。
遍历特征和阈值,寻找最佳分割点
for i in range(n):
values = np.expand_dims(X[:, i], axis=1)
unique_values = np.unique(values)
for threshold in unique_values:
p = 1
pred = np.ones(np.shape(y))
pred[X[:, i] < threshold] = -1
error = sum(w[y != pred])
对每个特征进行遍历,并尝试每个特征值作为分类阈值:
-
pred
初始化为 1,将所有小于阈值的样本预测为 -1。 -
error
计算预测结果和真实标签的误差。
判断是否需要反转预测方向
if error > 0.5:
error = 1 - error
p = -1
如果误差大于 0.5,则反转预测方向,将正类和负类交换(即 p = -1
)。
保存当前最优的分类器参数
if error < min_error:
estimator.label = p
estimator.threshold = threshold
estimator.feature_index = i
min_error = error
如果当前误差比 min_error
更小,则更新 estimator
的最佳参数:label
(方向),threshold
(阈值),和 feature_index
(特征索引)。
计算弱分类器权重
estimator.alpha = 0.5 * np.log((1.0 - min_error) / (min_error + 1e-9))
计算当前弱分类器的权重 alpha
,权重与分类误差成反比。误差越小,权重越大。
更新样本权重
preds = np.ones(np.shape(y))
negative_idx = (estimator.label * X[:, estimator.feature_index] < estimator.label * estimator.threshold)
preds[negative_idx] = -1
w *= np.exp(-estimator.alpha * y * preds)
w /= np.sum(w)
根据弱分类器的结果更新样本权重,预测错误的样本权重会增加。通过重新归一化 w
确保权重之和为 1。
3. 保存当前弱分类器
self.estimators.append(estimator)
将当前弱分类器添加到 self.estimators
列表中。
4. 预测方法 predict
def predict(self, X):
m = len(X)
y_pred = np.zeros((m, 1))
for estimator in self.estimators:
predictions = np.ones(np.shape(y_pred))
negative_idx = (estimator.label * X[:, estimator.feature_index] < estimator.label * estimator.threshold)
predictions[negative_idx] = -1
y_pred += estimator.alpha * predictions
y_pred = np.sign(y_pred).flatten()
return y_pred
-
初始化预测结果
y_pred
为 0。 - 对每个弱分类器的预测结果进行加权累加,最终根据正负符号返回预测结果。
总结
这个 Adaboost
类实现了一个基于决策树桩的 AdaBoost 算法。通过循环迭代,每一轮选择一个最佳弱分类器,并根据误差更新权重,逐步提高分类效果。最终预测结果为所有弱分类器的加权和。