综述
提升(boosting)方法是一种常用的统计学习方法,应用广泛且有效。在分类问题中,它通过改变训练
样本的权重,学习多个分类器,并将这些分类器进行线性组合,提高分类的性能。
“装袋”(bagging)和“提升”(boost)是构建组合模型的两种最主要的方法,所谓的组合模型是由多
个基本模型构成的模型,组合模型的预测效果往往比任意一个基本模型的效果都要好。
- 装袋:每个基本模型由从总体样本中随机抽样得到的不同数据集进行训练得到,通过重抽样得到不同 训练数据集的过程称为装袋。
- 提升:每个基本模型训练时的数据集采用不同权重,针对上一个基本模型分类错误的样本增加权重,使 得新的模型重点关注误分类样本
一、提升方法 AdaBoost 算法
在概率近似正确(probably approximately correct,PAC)学习的框架中,一个概念(一个类),如果存在一个多项式的学习算法能够学习它,并且正确率很高,那么就称这个概念是强可学习的;一个概念,如果存在一个多项式的学习算法能够学习它,学习的正确率仅比随机猜测略好,那么就称这个概念是弱可学习的。非常有趣的是,在 PAC 学习的框架下,一个概念是强可学习的充分必要条件是这个概念是弱可学习的。
对 AdaBoost 算法作如下说明:
class AdaBoost:
def __init__(self, n_estimators=50, learning_rate=1.0):
self.T = n_estimators # 迭代次数 -- 分类器个数
self.learning_rate = learning_rate # 移动步伐 -- 学习率
def init_args(self, datasets, labels):
self.X = datasets # 数据集
self.Y = labels # 标签
self.M, self.N = datasets.shape # 数据集格式
self.clf_sets = [] # 弱分类器数目和集合
self.weights = [1.0 / self.M] * self.M # 初始化weights
self.alpha = [] # G(x)系数 alpha
def _G(self, features, labels, weights):
m = len(features) # 获取行数
error = float("inf") # 无穷大
best_v = 0.0
# 单维features
features_min = min(features)
features_max = max(features)
n_step = (features_max - features_min + self.learning_rate) // self.learning_rate
# print('n_step:{}'.format(n_step))
direct, compare_array = None, None
for i in range(1, int(n_step)):
v = features_min + self.learning_rate * i
if v not in features:
# 误分类计算
compare_array_positive = np.array([1 if features[k] > v else -1 for k in range(m)])
compare_array_nagetive = np.array([-1 if features[k] > v else 1 for k in range(m)])
# 将与标签不符的预测的权重求和
weight_error_positive = sum([weights[k] for k in range(m)
if compare_array_positive[k] != labels[k]])
weight_error_nagetive = sum([weights[k] for k in range(m)
if compare_array_nagetive[k] != labels[k]])
if weight_error_positive < weight_error_nagetive:
weight_error = weight_error_positive
_compare_array = compare_array_positive
direct = 'positive'
else:
weight_error = weight_error_nagetive
_compare_array = compare_array_nagetive
direct = 'nagetive'
# print('v:{} error:{}'.format(v, weight_error))
if weight_error < error:
error = weight_error
compare_array = _compare_array
best_v = v
return best_v, direct, error, compare_array
# 计算alpha
def _alpha(self, error):
return 0.5 * np.log((1 - error) / error)
# 规范化因子
def _Z(self, weights, a, clf):
return sum([
weights[i] * np.exp(-1 * a * self.Y[i] * clf[i])
for i in range(self.M)
])
# 权值更新
def _w(self, a, clf, Z):
for i in range(self.M):
self.weights[i] = self.weights[i] * np.exp(
-1 * a * self.Y[i] * clf[i]) / Z
# G(x)的线性组合
def _f(self, alpha, clf_sets):
pass
def G(self, x, v, direct):
if direct == 'positive':
return 1 if x > v else -1
else:
return -1 if x > v else 1
def fit(self, X, y):
self.init_args(X, y) # 准备模型参数
for epoch in range(self.T): # 进行循环迭代
best_clf_error, best_v, clf_result = 100000, None, None
# 根据特征维度, 选择误差最小的
for j in range(self.N):
features = self.X[:, j] # 选取某一个特征
'''
v --- int类型 分类点
direct --- str类型--nagetive/positive 那个误分类少
error --- int类型 分类点对应的分类误差
compare_array --- 列表,预测误分类少下的预测标签
'''
v, direct, error, compare_array = self._G(features, self.Y, self.weights)
if error < best_clf_error:
best_clf_error = error
best_v = v
final_direct = direct
clf_result = compare_array
axis = j
# print('epoch:{}/{} feature:{} error:{} v:{}'.format(epoch, self.clf_num, j, error, best_v))
if best_clf_error == 0:
break
# 计算G(x)系数a
a = self._alpha(best_clf_error)
self.alpha.append(a)
# 记录分类器
self.clf_sets.append((axis, best_v, final_direct))
# 规范化因子
Z = self._Z(self.weights, a, clf_result)
# 权值更新
self._w(a, clf_result, Z)
# print('classifier:{}/{} error:{:.3f} v:{} direct:{} a:{:.5f}'.format(epoch+1, self.clf_num, error, best_v, final_direct, a))
# print('weight:{}'.format(self.weights))
# print('\n')
def predict(self, feature):
result = 0.0
for i in range(len(self.clf_sets)):
axis, clf_v, direct = self.clf_sets[i]
f_input = feature[axis]
result += self.alpha[i] * self.G(f_input, clf_v, direct)
# sign
return 1 if result > 0 else -1
def score(self, X_test, y_test):
right_count = 0
for i in range(len(X_test)):
feature = X_test[i]
if self.predict(feature) == y_test[i]:
right_count += 1
return right_count / len(X_test)
AdaBoost 算法还有另一个解释,即可以认为 AdaBoost 算法是模型为加法模型、损失函数为指数函数、
学习算法为前向分步算法时的二类分类学习方法。
这样,前向分步算法将同时求解从𝑚 = 1到𝑀所有参数
β
m
\beta_m
βm ,
γ
m
\gamma_m
γm的优化问题简化为逐次求解各个
β
m
\beta_m
βm ,
γ
m
\gamma_m
γm的优化问题。
AdaBoost 算法是前向分步加法算法的特例。这时,模型是由基本分类器组成的加法模型,损失函数是
指数函数。
二、提升树
提升树是以分类树或回归树为基本分类器的提升方法。提升树被认为是统计学习中性能最好的方法之
一。
提升方法实际采用加法模型(即基函数的线性组合)与前向分步算法。提升树模型可以表示为为决策树
的加法模型:
f
M
(
x
)
=
∑
m
=
1
M
T
(
x
;
Θ
m
)
f_{M}(x)=\sum_{m=1}^{M} T\left(x ; \Theta_{m}\right)
fM(x)=m=1∑MT(x;Θm)
其中,
T
(
x
;
Θ
m
)
T\left(x ; \Theta_{m}\right)
T(x;Θm) 表示决策树, }
Θ
m
\Theta_{m}
Θm 为决策树的参数,
M
M
M为树的个数
例