AdaBoost项目实战:参数择优与泛化能力

您所在的位置:网站首页 vivoy20s参数 AdaBoost项目实战:参数择优与泛化能力

AdaBoost项目实战:参数择优与泛化能力

2024-01-15 11:25| 来源: 网络整理| 查看: 265

本文以实验的方式验证了AdaBoost的强学习器理论,描述了模型的参数择优过程,和探讨了AdaBoost框架的泛化能力问题。最后,结合实验和理论,对AdaBoost框架进行总结。

目录:1. AdaBoost框架参数含义

2. 决策树与AdaBoost算法比较

3. AdaBoost模型的参数择优

4. 模型泛化能力探讨

5. 总结

AdaBoost框架参数含义

AdaBoostClassifier和AdaBoostRegressor框架的大部分参数相同,因此,下面我们一起讨论这些参数意义,如果两个类的有不同点会被指出。

1) base_estimator: AdaBoostClassifier和AdaBoostRegressor都有该参数,表示弱学习器,原则上可以选择任何一个弱学习器,不过需要支持样本权重。

2) algorithm: 这个参数只有AdaBoostClassifier有,主要是scikit-learn实现了两种AdaBoost分类算法,SAMME和SAMM.R。不同点在于弱学习器权重的计算方式不同。李航老师《统计学习方法》用的是SAMME算法。

3) loss:这个参数只有AdaBoostRegression,表示损失函数的选择。

4) n_estimators: AdaBoostClassifier和AdaBoostRegressor都有,表示弱学习器的个数。

5) learning_rate: AdaBoostClassifier和AdaBoostRegressor都有,表示每个弱学习器的权重缩减系数,意义等同于正则化项。

决策树与AdaBoost算法比较

AdaBoost算法结合多个弱分类器组成一个强分类器,为了形象化的表示这一含义。本节比较了决策树与AdaBoost算法结果,设置决策树的最大深度为1,相当于该决策树是一个弱分类器。

设置决策树最大深度为1:

estimatorCart = DecisionTreeClassifier(max_depth=1)

设置AdaBoost模型的基学习器为该决策树,弱学习器个数是200:

estimatorBoost = AdaBoostClassifier(base_estimator=estimatorCart,n_estimators=200)

下面是具体绘制学习曲线的代码:

生成训练和测试的学习曲线图函数import numpy as np import matplotlib.pyplot as plt from sklearn.model_selection import learning_curve def plot_learning_curve(estimator,title,X,y,ylim=None,cv=None, n_jobs=None,train_sizes=np.linspace(.1,1.0,10)): """ 生成训练和测试的学习曲线图 参数: --------------------- estimator: object type title: string 图表的标题 X: 类数组,形状(n_samples, n_features) 训练向量,其中n_samples为样本个数,n_features是特性的数量。 y: 类数组,形状(n_samples)或(n_samples, n_features),可选目标相对于X进行分类或回归; ylim:元组,形状(ymin, ymax),可选定义绘制的最小和最大y值。 cv:int,交叉验证生成器或可迭代的,可选的确定交叉验证拆分策略。 cv的可能输入是: -无,使用默认的3倍交叉验证, -整数,指定折叠的次数。 n_jobs:int或None,可选(默认=None) 并行运行的作业数。'None'的意思是1。 “-1”表示使用所有处理器。 train_sizes:类数组,形状(n_ticks,), dtype float或int 相对或绝对数量的训练例子,将用于生成学习曲线。如果dtype是float,则将其视为 训练集的最大大小的分数(这是确定的),即它必须在(0,1)范围内。 否则,它被解释为训练集的绝对大小。 注意,为了分类,样本的数量通常必须足够大,可以包含每个类的至少一个示例。 (默认:np.linspace(0.1, 1.0, 5)) """ plt.figure() plt.title(title) if ylim is not None: plt.ylim(*ylim) plt.xlabel("Training examples") plt.ylabel("Score") train_sizes, train_scores, test_scores = learning_curve( estimator, X, y, cv=cv, n_jobs=n_jobs, train_sizes=train_sizes) train_scores_mean = np.mean(train_scores, axis=1) train_scores_std = np.std(train_scores, axis=1) test_scores_mean = np.mean(test_scores, axis=1) test_scores_std = np.std(test_scores, axis=1) plt.grid() plt.fill_between(train_sizes, train_scores_mean - train_scores_std, train_scores_mean + train_scores_std, alpha=0.1, color="r") plt.fill_between(train_sizes, test_scores_mean - test_scores_std, test_scores_mean + test_scores_std, alpha=0.1, color="g") plt.plot(train_sizes, train_scores_mean, 'o-', color="r", label="Training score") plt.plot(train_sizes, test_scores_mean, 'o-', color="g", label="Cross-validation score") plt.legend(loc="best") return plt import matplotlib.pyplot as plt from sklearn.datasets import make_gaussian_quantiles from sklearn.model_selection import learning_curve from sklearn.model_selection import ShuffleSplit import numpy as np from sklearn.tree import DecisionTreeClassifier from sklearn.ensemble import AdaBoostClassifier # ########################## # 生成2维正态分布,生成的数据按分位数分为两类,50个样本特征,5000个样本数据 X,y = make_gaussian_quantiles(cov=2.0,n_samples=5000,n_features=50, n_classes=2,random_state=1) # 设置一百折交叉验证参数,数据集分层越多,交叉最优模型越接近原模型 cv = ShuffleSplit(n_splits=10,test_size=0.2,random_state=1) # 分别画出CART分类决策树和AdaBoost分类决策树的学习曲线 estimatorCart = DecisionTreeClassifier(max_depth=1) estimatorBoost = AdaBoostClassifier(base_estimator=estimatorCart, n_estimators=270) # 画CART决策树和AdaBoost的学习曲线 estimatorTuple = (estimatorCart,estimatorBoost) titleTuple =("decision learning curve","adaBoost learning curve") title = "decision learning curve" for i in range(2): estimator = estimatorTuple[i] title = titleTuple[i] plot_learning_curve(estimator,title, X, y, cv=cv) plt.show()

学习曲线分析:第一张图表示随着样本数的增加训练精度和测试精度稳定在0.5左右,与随机分类的概率相等,这表明模型处于高偏差状态,是一种弱分类器。第二张图表示随着样本数的增加测试精度稳定增长,当增长到4000例时测试精度接近85%,这表明分类模型的性能较好,是一种强分类器。

结论:AdaBoost可以结合多个弱分类器组成强分类器。

AdaBoost模型的参数择优

上节为了证明AdaBoost的强学习器理论,简单的设置了弱分类器个数和决策树深度,并未对其他参数进行设置,模型还有较大的优化空间。因此,本节讨论了如何对AdaBoost模型进行参数择优。

集成式模型包括框架和弱学习器,我建议集成式模型的参数择优首先从框架开始,框架参数择优的过程中默认弱学习器是固定的,再对弱学习器的重要参数进行择优,此时框架的参数是择优后的参数。

因此,AdaBoost模型首先对框架进行参数择优,然后再对弱学习器进行参数择优,参数择优算法常常采用交叉验证法。

1) 框架参数择优设置弱分类器个数,我们首先对n_estimators进行网格搜索:

# 对框架参数 若学习器个数进行择优 param_test1 = {"n_estimators":range(150,300,50)} # 框架参数择优 gsearch1 = GridSearchCV(estimator=AdaBoostClassifier(estimatorCart), param_grid=param_test1,scoring="roc_auc",cv=5) gsearch1.fit(X,y) print(gsearch1.best_params_,gsearch1.best_score_)

打印结果:{"n_estimators":250} 0.9360104

因此,第一次优化的最佳弱学习器个数:250。再次优化弱学习器个数,第一次优化是大致估计最佳参数的值,第二次优化在最佳参数的附近找最优值,下面代码是在最优参数相对误差30的范围内重新搜寻:

# 继续优化弱学习器个数,在最优学习器个数的范围内再次搜寻 param_test2 = {"n_estimators":range(n_estimator1-30,n_estimators1+30,10)} gsearch2 = GridSearchCV(estimator=AdaBoostClassifier(estimatorCart), param_grid=param_test2,scoring="roc_auc",cv=5) gsearch2.fit(X,y) print(gsearch2.best_params_,gsearch2.best_score_)

打印结果:{'n_estimators':270} 0.938772因此,第二次优化的最佳弱学习器个数:270其实还可以按照第二次优化思想再次缩小参数的搜寻范围,这里就不继续了。

2) 弱学习器参数择优

AdaBoost框架有很多弱学习器可以选择,本节只讨论弱学习器是决策树的情况,这里主要对决策树深度和最小可划分节点数进行参数择优,其他参数可按照同样的思想去优化。

弱学习器的复杂度很低,因此决策树深度在1~2范围内搜寻,最小可划分节点数根据经验在18~22范围内搜寻。对于训练数据很大的情况,最小可划分节点数基本没起作用,训练数据很小的情况可考虑该参数。

弱学习器参数优化代码:

for i in range(1,3): # 决策树最大深度循环 print(i) for j in range(18,22): print(j) bdt=AdaBoostClassifier(DecisionTreeClassifier(max_depth=i, min_samples_split=j),n_estimators=n_estimators2) cv_result = cross_validate(bdt,X,y,return_train_score=False,cv=5) cv_value_vec = cv_result["test_score"] cv_mean = np.mean(cv_value_vec) if cv_mean>=score: score = cv_mean tree_depth = i samples_split = j

代码中的n_estimators2的值等于270。因为训练数据比较大,所以弱学习器的最小可划分节点数(min_samples_split)没起作用,我们设置该参数为20,最后得到最优决策树的最大深度等于1。

用该最优参数重新构建模型,并输出测试结果。

bdt = AdaBoostClassifier(DecisionTreeClassifier(max_depth=tree_depth), n_estimators=n_estimators2) bdt.fit(X_train,y_train) print(bdt.score(X_test,y_test))

测试准确率:85.6%

3) 重新绘制学习曲线

参数优化后的学习曲线较第一节的学习曲线略有提升,相信如果我们再增加训练数据,测试准确率还会提高。

模型泛化能力的探讨

AdaBoost框架的泛化问题是一个很容易让人疑惑的点,网上查的资料很容易让人混淆,下面我通过实验的方式对某些结论进行验证(样本数一定的情况下):

1) 决策树深度设置为1时,观察迭代次数与测试误差的关系:

结论:弱学习器的复杂度很小,当迭代次数增加时,测试误差减小,泛化能力增强。

2) 决策树深度设置为10时,观察迭代次数与测试误差的关系:

结论:弱学习器的复杂度较大,当迭代次数增加时,测试误差无明显变换,即泛化能力没有增强,模型处于过拟合状态。

3) 探讨学习率与迭代次数的关系

import matplotlib.pyplot as plt from sklearn.ensemble import AdaBoostClassifier from sklearn.tree import DecisionTreeClassifier from sklearn.datasets import make_gaussian_quantiles from sklearn.model_selection import learning_curve from sklearn.model_selection import ShuffleSplit import numpy as np from sklearn.tree import DecisionTreeClassifier from sklearn.ensemble import AdaBoostClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score from sklearn.metrics import zero_one_loss # ########################## n_estimators = 200 # 生成2维正态分布,生成的数据按分位数分为两类,50个样本特征,5000个样本数据 X,y = make_gaussian_quantiles(cov=2.0,n_samples=5000,n_features=50, n_classes=2,random_state=1) # 数据划分为训练集和测试集 X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=1) # 根据上一节的参数择优,选择最优参数来构建模型 estimatorCart = DecisionTreeClassifier(max_depth=1) dt_stump1 = AdaBoostClassifier(base_estimator=estimatorCart, n_estimators=n_estimators,learning_rate=0.8) dt_stump2 = AdaBoostClassifier(base_estimator=estimatorCart, n_estimators=n_estimators,learning_rate=0.1) dt_stump1.fit(X_train,y_train) dt_stump_err1 = 1.0 - dt_stump1.score(X_test,y_test) # dt_stump2.fit(X_train,y_train) dt_stump_err2 = 1.0 - dt_stump2.score(X_test,y_test) # ########### test_errors1 = [] # 每迭代一次,得到一个测试结果 ada_discrete_err1 = np.zeros((n_estimators,)) ada_discrete_err2 = np.zeros((n_estimators,)) for i,ypred in enumerate(dt_stump1.staged_predict(X_test)): ada_discrete_err1[i] = zero_one_loss(ypred,y_test) for i,ypred in enumerate(dt_stump2.staged_predict(X_test)): ada_discrete_err2[i] = zero_one_loss(ypred,y_test) # 画出迭代次数与准确率的关系 fig = plt.figure() ax = fig.add_subplot(111) ax.plot(np.arange(n_estimators) + 1, ada_discrete_err1, label='learning rate = 0.8', color='red') ax.plot(np.arange(n_estimators) + 1, ada_discrete_err2, label='learning rate = 0.1', color='green') ax.set_ylim((0.0, 1)) ax.set_xlabel('n_estimators') ax.set_ylabel('error rate') leg = ax.legend(loc='upper right', fancybox=True) leg.get_frame().set_alpha(0.7) plt.show()

结论:当学习率较大时,即步长较大,对于同样的弱学习器个数,学习率大的泛化性能好。

总结:(1) 弱学习器的复杂度是我们提高模型泛化能力最大的影响因素,若数据集含有很大的噪声,我们也认为该数据的复杂度很高,复杂度很高的模型,增加弱学习器的数目不能增加模型的泛化能力,我们需要想办法去降低模型的复杂度。(2) 学习率越大,那么在相同的弱学习器下,泛化能力越强。

总结

AdaBoost是通过一系列的弱学习器组成强学习器的方法,切记,基学习器的复杂度尽量小,可通过提高弱学习器数目的方式提高泛化能力。但是若数据含有较大的噪声或弱学习器模型复杂度较高,提高弱学习器个数并不能提高泛化能力。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3