完整的实验代码在我的github上👉QYHcrossover/ML-numpy: 机器学习算法numpy实现 (github.com) 欢迎star⭐
当你需要从一个弱分类器中得到强分类器的时候,Adaboost算法是一个很好的选择。Adaboost 是一种集成学习算法,主要用于二分类问题。它通过对多个分类器的集成来提高分类性能。Adaboost 会对数据集进行多次训练,并将每次训练得到的分类器加权组合,最终形成一个强分类器。
Adaboost 原理
Adaboost 的核心思想是将若干个弱分类器组合成一个强分类器。弱分类器是指分类准确率略高于随机猜测的分类器,例如决策树的深度较浅、逻辑回归的迭代次数较少等。 Adaboost 算法的关键在于为每个弱分类器分配一个权重,用于计算最终分类器的输出。
Adaboost 算法的具体流程如下:
- 初始化训练数据集的权重向量 w 1 = ( w 1 , 1 , w 1 , 2 , . . . , w 1 , N ) w_1 = (w_{1,1},w_{1,2},...,w_{1,N}) w1=(w1,1,w1,2,...,w1,N),其中 N N N 表示训练数据集的大小, w 1 , i w_{1,i} w1,i 表示第 i i i 个样本的权重,通常初始值为 1 / N 1/N 1/N。
- 对于
m
=
1
,
2
,
.
.
.
,
M
m=1,2,...,M
m=1,2,...,M,进行以下步骤:
- 使用当前权重向量 w m w_m wm 训练一个弱分类器 h m ( x ) h_m(x) hm(x)。
- 计算弱分类器 h m ( x ) h_m(x) hm(x) 的误差率 ϵ m \epsilon_m ϵm,其中 ϵ m \epsilon_m ϵm 定义为分类器 h m ( x ) h_m(x) hm(x) 在当前权重向量下,被误分类的样本的权重之和,即 ϵ m = ∑ i = 1 N w m , i I ( y i ≠ h m ( x i ) ) \epsilon_m=\sum_{i=1}^{N}w_{m,i}I(y_i \neq h_m(x_i)) ϵm=∑i=1Nwm,iI(yi=hm(xi)),其中 I I I 为指示函数,当 y i ≠ h m ( x i ) y_i \neq h_m(x_i) yi=hm(xi) 时为 1 1 1,否则为 0 0 0。
- 计算弱分类器 h m ( x ) h_m(x) hm(x) 的权重 α m \alpha_m αm,其中 α m \alpha_m αm 定义为 α m = 1 2 l n ( 1 − ϵ m ϵ m ) \alpha_m = \frac{1}{2}ln(\frac{1-\epsilon_m}{\epsilon_m}) αm=21ln(ϵm1−ϵm)。
- 更新权重向量 w m + 1 w_{m+1} wm+1,其中 w m + 1 , i = w m , i Z m e x p ( − α m y i h m ( x i ) ) w_{m+1,i} = \frac{w_{m,i}}{Z_m}exp(-\alpha_m y_i h_m(x_i)) wm+1,i=Zmwm,iexp(−αmyihm(xi)),其中 Z m Z_m Zm 是规范化因子,使得 w m + 1 w_{m+1} wm+1 成为一个概率分布,即 Z m = ∑ i = 1 N w m , i e x p ( − α m y i h m ( x i ) ) Z_m=\sum_{i=1}^{N}w_{m,i}exp(-\alpha_m y_i h_m(x_i)) Zm=∑i=1Nwm,iexp(−αmyihm(xi))。
- 得到最终的分类器 H ( x ) = sign ( ∑ m = 1 M α m h m ( x ) ) H(x)=\text{sign}(\sum_{m=1}^{M}\alpha_m h_m(x)) H(x)=sign(∑m=1Mαmhm(x))。
Adaboost算法的原理是基于这样一个事实:虽然弱分类器可能不能正确地分类训练数据,但是通过组合它们,我们可以得到一个更强的分类器。在每次迭代中,Adaboost将更多的关注放在上一次分类错误的样本上,以便下一次迭代时它们被正确分类的概率更高。通过这种方式,Adaboost算法不断地优化分类器,使其在分类训练数据时的准确性不断提高。
Adaboost代码实现
下面是使用Python实现Adaboost算法的代码。我们将使用乳腺癌数据集来演示Adaboost算法的应用。在此代码中,我们定义了一个MyAdaboost类,其中包含fit和predict方法,用于训练和预测Adaboost模型。在fit方法中,我们使用_best_split方法找到最佳划分点,并使用_G方法构造弱分类器的决策函数g(X)。在predict方法中,我们计算加权的弱分类器的预测结果,并返回最终预测标签。最后,我们使用score方法计算测试数据集上的分类准确度。
# 构建Adaboost类
class MyAdaboost:
def __init__(self,n_estimators):
self.n_estimators = n_estimators
self.clfs = [lambda x:0 for i in range(self.n_estimators)]
self.alphas = [0 for i in range(self.n_estimators)]
self.weights = None
# 构造弱分类器的决策函数g(X)
def _G(self,fi,fv,direct):
assert direct in ["positive","nagetive"]
def _g(X):
if direct == "positive":
predict = (X[:,fi] <= fv) * -1 # which <= value assign -1 else 0
else:
predict = (X[:,fi] > fv) * -1 # which > value assign 0 else -1
predict[predict == 0] = 1
return predict
return _g
#选择最佳的划分点,即求出fi和fv
def _best_split(self,X,y,w):
best_err = 1e10
best_fi = None
best_fv = None
best_direct = None
for fi in range(X.shape[1]):
series = X[:,fi]
for fv in np.sort(series):
predict = np.zeros_like(series,dtype=np.int32)
# direct = postive
predict[series <= fv] = -1
predict[series > fv] = 1
err = np.sum((predict != y)* 1 * w)
# print("err = {} ,fi={},fv={},direct={}".format(err,fi,fv,"postive"))
if err < best_err:
best_err = err
best_fi = fi
best_fv = fv
best_direct = "positive"
# direct = nagetive
predict = predict * -1
err = np.sum((predict != y) * 1 * w)
if err < best_err:
best_err = err
best_fi = fi
best_fv = fv
best_direct = "nagetive"
# print("err = {} ,fi={},fv={},direct={}".format(err,fi,fv,"nagetive"))
return best_err,best_fi,best_fv,best_direct
def fit(self,X_train,y_train):
self.weights = np.ones_like(y_train) / len(y_train)
for i in tqdm(range(self.n_estimators)):
err,fi,fv,direct = self._best_split(X_train,y_train,self.weights)
# print(i,err,fi,fv,direct)
#计算G(x)的系数alpha
alpha = 0.5 * np.log((1-err)/err) if err !=0 else 1
# print("alpha:",alpha)
self.alphas[i] = alpha
#求出G
g = self._G(fi,fv,direct)
self.clfs[i] = g
if err == 0: break
#更新weights
self.weights = self.weights * np.exp(-1 * alpha * y_train * g(X_train))
self.weights = self.weights / np.sum(self.weights)
# print("weights :",self.weights)
首先初始化模型参数,也就是__init__
函数的主要含义
- n_estimators表示要构建的基分类器数量;
- clfs是一个列表,用于存储每个基分类器的决策函数,初始值为0;
- alphas是一个列表,用于存储每个基分类器的权重,初始值为0;
- weights是一个数组,用于存储每个样本的权重,初始值为1/len(y_train)。
其次通过fit
函数训练n个基分类器,主要流程是:
- 通过_best_split函数选择最佳的划分点,即求出fi和fv;
- 计算G(x)的系数alpha,更新alphas列表;
- 求出G,更新clfs列表;
- 更新weights数组;
- 如果err为0,则停止训练。
在fit
函数中best_split函数
是该算法的核心之一。best_split函数用于选择最佳的划分点,即求出fi和fv,其中fi表示选择哪个特征,fv表示该特征的划分值。
具体实现过程如下:
- 对于每个特征fi,在该特征上从小到大排序,枚举每个排好序的取值fv。
- 对于每个fv,先考虑将小于等于fv的样本划分到负类(-1),大于fv的样本划分到正类(+1)的情况(记为"positive")。
- 计算划分错误率,即被误分类的样本的权重之和。如果当前的错误率小于已有最小错误率,则更新最小错误率、最佳划分特征fi、最佳划分值fv、划分方向(“positive”)。
- 接下来,再考虑将小于等于fv的样本划分到正类(+1),大于fv的样本划分到负类(-1)的情况(记为"nagetive")。
- 计算划分错误率,如果当前的错误率小于已有最小错误率,则更新最小错误率、最佳划分特征fi、最佳划分值fv、划分方向(“nagetive”)。
- 返回最佳划分点。
在构建完fit
训练模型的主要逻辑后,我们再来简单看一下怎么测试和评估模型,主要用到了predict
函数和score函数
,
- predict函数:predict函数的作用是对输入的测试数据进行分类预测。具体实现是对每个弱分类器预测结果进行加权和,最终根据加权和的符号来判断属于哪一类。
- score函数:score函数的作用是对模型的性能进行评估。具体实现是在预测阶段,将预测结果与真实标签进行比较,计算准确率。
def predict(self,X_test):
y_p = np.array([self.alphas[i] * self.clfs[i](X_test) for i in range(self.n_estimators)])
y_p = np.sum(y_p,axis=0)
y_predict = np.zeros_like(y_p,dtype=np.int32)
y_predict[y_p>=0] = 1
y_predict[y_p<0] = -1
return y_predict
def score(self,X_test,y_test):
y_predict = self.predict(X_test)
return np.sum(y_predict == y_test)/len(y_predict)
最后我们再来看一下主函数的主要内容:
if __name__ == "__main__":
breast_cancer = load_breast_cancer()
X = breast_cancer.data
y = breast_cancer.target
y[y==0] = -1
# 划分数据
X_train,X_test,y_train,y_test = train_test_split(X,y)
print(X_train.shape,X_test.shape)
clf = MyAdaboost(100)
clf.fit(X_train,y_train)
print(clf.score(X_test,y_test))
主函数的主要流程如下:
- 加载乳腺癌数据集,并将类别标签从0/1转换为-1/1。
- 将数据集分成训练集和测试集。
- 创建一个MyAdaboost对象clf,并设置n_estimators参数为100。
- 使用clf对象的fit方法在训练集上进行拟合,得到100个弱分类器。
- 使用clf对象的score方法在测试集上计算分类器的准确率,并打印输出。
总结
该篇博客主要介绍了Adaboost算法的原理和实现过程,Adaboost是一种基于弱分类器的集成学习算法,它的核心思想是通过多个弱分类器的集成来构建一个更强大的分类器。文章首先介绍了Adaboost算法的原理,包括基本流程和重要的公式推导,然后详细介绍了如何使用Python实现Adaboost算法,包括构建Adaboost类和实现fit、predict和score等方法。最后,通过对乳腺癌数据集的实验,展示了Adaboost算法在二分类问题上的应用效果。
完整的实验代码在我的github上👉QYHcrossover/ML-numpy: 机器学习算法numpy实现 (github.com) 欢迎star⭐