【Stacking改进】基于随机采样与精度加权的Stacking算法
【Stacking改进】基于随机采样与精度加权的Stacking算法
摘要
近年来,人工智能的强势崛起让我们领略到人工智能技术的巨大潜力,机器学习也被广泛应用于各个领域,并取得不错的成果。本文以Kaggle竞赛House Prices的房价数据为实验样本,借鉴Bagging的自助采样法和k折交叉验证法,构建一种基于伪随机采样的Stacking集成模型,用于房价预测。首先利用GBDT对数据集进行简单训练,并得到各个特征重要性。接着对数据集进行多次随机采样,然后根据特征重要性进行属性扰动,组成多个训练数据子集和验证数据子集。用这些数据子集训练基模型,并计算验证集的均方根误差和预测结果,根据误差分配权重。根据各个基模型预测结果组成第二层的元模型,最后在测试数据集上进行房价预测。实验结果表明,基于随机采样和精度加权的Stacking集成模型的均方根误差小于所有基分类器和同结构的经典Stacking集成方法。
Stacking算法理论基础
Stacking是一种分层模型集成框架,在1992年被Wolpert提出。Stacking集成可以有多层的情况,但通常会设计两层,第一层由多种基模型组成,输入为原始训练集,而输出为各种基模型的预测值,而第二层只有一个元模型,对第一层的各种模型的预测值和真实值进行训练,从而得到完成的集成模型。同理,预测测试集的过程也要先经过所有基模型的预测,组成第二层的特征,再用第二层的元模型预测出最终的结果。为了防止模型过拟合的情况,一般Stacking算法在第一层训练基模型时会结合k折交叉验证法。以五折交叉验证法为例,Stacking算法的过程如下图所示。
传统Stacking代码
# 定义一个交叉评估函数 Validation function
n_folds = 5def rmsle_cv(model):kf = KFold(n_folds, shuffle=True, random_state=42).get_n_splits(train.values)rmse= np.sqrt(-cross_val_score(model, train.values, target_variable, scoring="neg_mean_squared_error", cv = kf))return(rmse)
# 堆叠模型(Stacking Averaged Models) score: 0.1087 (0.0061)
class StackingAveragedModels(BaseEstimator, RegressorMixin, TransformerMixin):def __init__(self, base_models, meta_model, n_folds=5):self.base_models = base_modelsself.meta_model = meta_modelself.n_folds = n_foldsdef fit(self, X, y):self.base_models_ = [list() for x in self.base_models] # 4×5 list 存放训练好的模型self.meta_model_ = clone(self.meta_model) # 复制基准模型,因为这里会有多个模型kfold = KFold(n_splits=self.n_folds, shuffle=True, random_state=156)# 训练基准模型,基于基准模型训练的结果导出成特征# that are needed to train the cloned meta-modelout_of_fold_predictions = np.zeros((X.shape[0], len(self.base_models)))for i, model in enumerate(self.base_models):for train_index, holdout_index in kfold.split(X, y): #分为预测holdout_index和训练train_indexinstance = clone(model)self.base_models_[i].append(instance)instance.fit(X[train_index], y[train_index])y_pred = instance.predict(X[holdout_index])out_of_fold_predictions[holdout_index, i] = y_pred# 将基准模型预测数据作为特征用来给meta_model训练self.meta_model_.fit(out_of_fold_predictions, y)return selfdef predict(self, X):meta_features = np.column_stack([np.column_stack([model.predict(X) for model in base_models]).mean(axis=1)for base_models in self.base_models_ ])
# meta_features = np.c_[meta_features,X[:,1]]return self.meta_model_.predict(meta_features)from sklearn.linear_model import LinearRegression
meta_model = KRR
stacked_averaged_models = StackingAveragedModels(base_models = (ENet, GBoost, KRR, lasso),meta_model = meta_model,n_folds=10)
score = rmsle_cv(stacked_averaged_models)
print("Stacking Averaged models score: {:.4f} ({:.4f})".format(score.mean(), score.std()))
Stacking Averaged models score: 0.1087 (0.0061)
Stacking改进
改进思路
本文对传统的Stacking算法进行研究改进,以Kaggle竞赛House Prices的房价数据为实验样本,通过Kaggle测试得分验证改进方法的可行性。本文以以下的方式对传统Stacking算法进行改进:
使用无放回抽样得到数据子集。目前传统的Stacking算法是采用五折交叉验证法,将训练数据分成5等份,依次选择其中一份作为验证子集,而其他四份作为训练子集用于模型训练,用训练好的基模型去预测验证子集,预测结果作为第二层的特征。而本文的模型则选择随机不放回抽样,比如连续20次随机抽取80%的样本,组成20个独立的数据子集。
根据概率随机选取特征。数据集经过数据处理和特征工厂后会产生很多特征,尤其是对离散特征进行独热编码,使得特征空间会变得非常大,而且存在很多冗余特征。因此本文利用GBDT对数据集进行简单训练,并得到各个特征重要性,组成总和为1的概率列表。利用这个概率列表随机选取特征,可过滤冗余特征,构造效率更高、消耗更低的独立的预测模型。
根据训练集的测试精度进行测试集的权重分配。传统的Stacking算法是采用五折交叉验证法,将数据集划分成五等份,由五组数据子集构成5个基模型,在第一层预测测试集时,取5个基模型的预测结果的平均值作为第二层的特征。这里可能存在数据划分不均,而导致预测效果不佳的情况。因此本文根据基模型的测试精度对预测结果进行加权平均,得到结果作为第二层的特征。
改进Stacking代码
subsample函数是对数据集进行样本与特征的采样,并记录采样情况,因为预测的时候需要对测试集的特征进行相同的采样。
.
改进的算法有三个超参数:
- n_tree:基模型个数T
- ratio_sample:样本采样比例a
- ratio_feature:特征采样比例b
.
首先先用GBoost进行简单训练,得到特征重要性列表
.
在stacking框架第一层,对每一个基模型进行T次拷贝,根据样本采样比例a对样本进行T次随机采样,然后再根据特征采样比例b和特征重要性列表进行特征选择,得到T个训练子集和T个验证子集。用训练子集分别对基模型进行训练,然后将对相应的验证子集的预测结果作为第二层元模型的输入特征。同时根据验证集的预测值与真实值的误差,给T个基模型分配权重。误差越大,权重越低。
权重计算公式:
import random
from numpy import median
def subsample(dataset_x, ratio_sample, ratio_feature, i, list_fearure): # 创建数据集的随机子样本"""random_forest(评估算法性能,返回模型得分)Args:dataset 训练数据集ratio 训练数据集的样本比例,特征比例Returns:sample 随机抽样的训练样本序列号test_list 随机抽样后的剩下的测试样本序列号feature 随机抽样的特征序列号"""random.seed(i) # 固定随机值sample = list()# 训练样本的按比例抽样。# round() 方法返回浮点数x的四舍五入值。n_sample = round(len(dataset_x) * ratio_sample)n_feature = round(dataset_x.shape[1] * ratio_feature)sample = random.sample(range(len(dataset_x)), n_sample)
# feature = random.sample(range(dataset_x.shape[1]), n_feature)feature = np.random.choice(a=range(dataset_x.shape[1]), size=n_feature, replace=False, p=list_fearure)test_list = list(set(range(len(dataset_x))) - set(sample))return sample, test_list, feature# RF堆叠模型(RF Stacking Averaged Models) 0.1158 (0.0048)
class RfStackingAveragedModels(BaseEstimator, RegressorMixin, TransformerMixin):def __init__(self, base_models, meta_model, n_tree=20, ratio_sample=1, ratio_feature=1,list_fearure=[]):self.base_models = base_modelsself.meta_model = meta_modelself.n_tree = n_treeself.ratio_sample = ratio_sampleself.ratio_feature = ratio_featureself.list_fearure = list_fearuredef fit(self, X, y):self.base_models_ = [list() for x in self.base_models] # 4×5 list 存放训练好的模型self.meta_model_ = clone(self.meta_model) # 复制基准模型,因为这里会有多个模型self.list_weight = [list() for x in self.base_models] # 4×20 list 存放预测的权重self.list_feature = [list() for x in self.base_models] # 4×20 list 存放特征n_tree = self.n_treeratio_sample = self.ratio_sampleratio_feature = self.ratio_featurelist_fearure = self.list_fearure# 训练基准模型,基于基准模型训练的结果导出成特征# that are needed to train the cloned meta-modelrf_predictions = [list() for x in self.base_models]rf_y = []rf_x0 = []rf_x1 = []for i, model in enumerate(self.base_models):out__predictions = np.zeros((X.shape[0], n_tree))for j in range(n_tree):train_list, test_list, feature = subsample(X, ratio_sample, ratio_feature, j, list_fearure)instance = clone(model)self.base_models_[i].append(instance)instance.fit(X[np.ix_(train_list, feature)], y[train_list])y_pred = instance.predict(X[np.ix_(test_list, feature)])# list(set(feature)|set(list_fearure))rf_predictions[i].extend(y_pred)if i == 0:rf_x0.extend(test_list)rf_x1.extend(feature)rf_y.extend(y[test_list])mse = mean_squared_error(y_pred, y[test_list])self.list_weight[i].append(mse)out__predictions[:, j] = instance.predict(X[np.ix_(range(X.shape[0]), feature)])self.list_feature[i].append(feature) # 权重计算sum_weight = sum(self.list_weight[i])num_weight = len(self.list_weight[i])mid_weight = median(self.list_weight[i])for j in range(num_weight):self.list_weight[i][j] = (sum_weight - self.list_weight[i][j]) / sum_weight / (num_weight-1)# 将基准模型预测数据作为特征用来给meta_model训练rf_x = pd.DataFrame(rf_predictions)rf_x = rf_x.T
# rf_x['area'] = rf_x0self.meta_model_.fit(rf_x, rf_y)return selfdef predict(self, X):meta_features = np.column_stack([np.column_stack([model.predict(X[np.ix_(range(X.shape[0]), self.list_feature[i][j])])*self.list_weight[i][j] for j, model in enumerate(base_models)]).sum(axis=1)for i, base_models in enumerate(self.base_models_) ])
# meta_features = np.c_[meta_features,X[:,1]]return self.meta_model_.predict(meta_features)GBoost.fit(train,target_variable)
list_fearure = GBoost.feature_importances_
list_non = list(np.nonzero(list_fearure)[0])
meta_model = GBoost
rf_stacked_averaged_models = RfStackingAveragedModels(base_models = (ENet, KRR, lasso),meta_model = meta_model,n_tree=20, ratio_sample=0.8, ratio_feature=0.6, list_fearure=list_fearure)score = rmsle_cv(rf_stacked_averaged_models)
print("RF Averaged models score: {:.4f} ({:.4f})".format(score.mean(), score.std()))
RF Averaged models score: 0.1158 (0.0048)
基模型参数设置如下
# LASSO回归(LASSO Regression) Lasso score: 0.1101 (0.0058)
lasso = make_pipeline(RobustScaler(), Lasso(alpha =0.0005, random_state=1))
score = rmsle_cv(lasso)
print("\nLasso score: {:.4f} ({:.4f})\n".format(score.mean(), score.std()))# 岭回归(Kernel Ridge Regression) Lasso score: 0.1152 (0.0043)
KRR = make_pipeline(RobustScaler(), KernelRidge(alpha=0.6, kernel='polynomial', degree=2, coef0=2.5))
score = rmsle_cv(KRR)
print("\nLasso score: {:.4f} ({:.4f})\n".format(score.mean(), score.std())) # 弹性网络回归(Elastic Net Regression) Lasso score: 0.1100 (0.0059)
ENet = make_pipeline(RobustScaler(), ElasticNet(alpha=0.0005, l1_ratio=.9, random_state=3))
score = rmsle_cv(ENet)
print("\nLasso score: {:.4f} ({:.4f})\n".format(score.mean(), score.std())) # 提升树(Gradient Boosting Regression): Lasso score: 0.1180 (0.0088)
GBoost = GradientBoostingRegressor(n_estimators=300, learning_rate=0.05,max_depth=4, max_features='sqrt',min_samples_leaf=15, min_samples_split=10, loss='huber', random_state=5)score = rmsle_cv(GBoost)
print("\nLasso score: {:.4f} ({:.4f})\n".format(score.mean(), score.std()))
结果
模型 | 均方根误差 |
---|---|
岭回归 | 0.13666 |
LASSO回归 | 0.13181 |
弹性网络回归 | 0.13174 |
梯度提升树 | 0.13278 |
传统stacking集成模型 | 0.12254 |
改进stacking集成模型 | 0.12060 |
引用
本文数据来源于Kaggle竞赛House Prices的房价数据,测试结果通过Kaggle竞赛上传数据得到。
本次数据处理主要源于https://my.oschina.net/Kanonpy/blog/3076731
[1]: House Prices - Advanced Regression Techniques[EB/OL]. https://www.kaggle.com/c/house-prices-advanced-regression-techniques,2016-8-30.
[2]: https://my.oschina.net/Kanonpy/blog/3076731
[3]: 鲁莹, 郑少智.Stacking 学习与一般集成方法的比较研究[D].暨南大学,2017.
[4]: 覃智全. Stacking集成分类器优化算法研究[D].国防科学技术大学,2016.
[5]: 张笑铭,王志君,梁利平.一种适用于卷积神经网络的Stacking算法[J].计算机工程,2018,44(04):243-247.
[6]: 徐慧丽. Stacking算法的研究及改进[D].华南理工大学,2018.
[7]: 陈宇韶. 基于特征选择与改进Stacking算法的股价预测研究[D].南华大学,2018.
【Stacking改进】基于随机采样与精度加权的Stacking算法相关推荐
- 高动态环境下基于随机可及集的Path-Guided APF算法的Motion Planning
文章目录 摘要 引言 相关工作 问题假设 动态障碍物 Relative robot-obstacle dynamics(运动学) SR Sets for Collision Avoidance 方法! ...
- 基于随机分形搜索算法的函数寻优算法
文章目录 一.理论基础 1.随机分形搜索算法 2.SFS算法流程图 二.仿真实验与分析 三.参考文献 一.理论基础 1.随机分形搜索算法 随机分形算法(Stochastic Fractal Searc ...
- 【随机共振】基于随机共振的高灵敏度GPS信号捕获算法
算法结构图 首先input输入到SR 这个语句意思就是每次输入一段数据进行处理,因为这个系统是实时反馈的系统,所以在处理的时候,必须是一段段处理,而不能和原来一样一次性进行处理,所以我们每次处理的数据 ...
- 自动驾驶路径规划——基于概率采样的路径规划算法(RRT、RRT*)
目录 1. RRT算法背景 1.1 RRT算法核心思想 1.2 RRT算法优缺点 2. 经典RRT算法 2.1 RRT算法流程 2.2 RRT伪代码 3. 基于目标概率采样 4. RRT*算法 4.1 ...
- PCL 点云分割与分类 Segmentation RANSAC随机采样一致性 平面模型分割 欧氏距离分割 区域聚类分割算法 最小分割算法 超体聚类 渐进式形态学滤波器
点云分割 博文末尾支持二维码赞赏哦 _ 点云分割是根据空间,几何和纹理等特征对点云进行划分, 使得同一划分内的点云拥有相似的特征,点云的有效分割往往是许多应用的前提, 例如逆向工作,CAD领域对零件的 ...
- 机器学习系列|基于随机森林的生存分析模型-R实战
机器学习系列|基于随机森林的生存分析模型-R实战 随机生存森林 随机生存森林通过训练大量生存树,以表决的形式,从个体树之中加权选举出最终的预测结果. 构建随机生存森林的一般流程为: Ⅰ. 模型通过&q ...
- 基于随机无迹σ变异的改进HHO算法
文章目录 一.理论基础 1.哈里斯鹰优化算法HHO 2.改进哈里斯鹰优化算法OSHHO (1)伪对立和伪反射学习机制 (2)随机无迹点变异机制 (3)能量因子非线性调整机制 (4)OSHHO算法执行流 ...
- python随机森林筛选变量_一种基于随机森林的改进特征筛选算法
刘云翔 陈斌 周子宜 摘 要: 肝癌是一种我国高发的消化系统恶性肿瘤,患者死亡率高,威胁极大.而其预后情况通常只能通过医生的专业知识和经验积累来粗略判断,准确率较差.因此文中在分析随机森林算法的基本 ...
- 基于蜣螂算法改进的随机森林回归算法 - 附代码
基于蜣螂算法改进的随机森林回归算法 - 附代码 文章目录 基于蜣螂算法改进的随机森林回归算法 - 附代码 1.数据集 2.RF模型 3.基于蜣螂算法优化的RF 4.测试结果 5.Matlab代码 6. ...
最新文章
- 斯坦福大学马超:探寻「隐式偏差」的完整理论框架
- 一句话生成数字人形象、昆仑芯2量产…百度大脑升级7.0,王海峰:技术更强了门槛却更低...
- 【vue】介绍一个vuejs 和 element 搭建的一个后台管理界面
- qt布局嵌套_PyQt5 笔记(01):嵌套布局
- java判断文件或者文件夹
- 【励志】公子龙:我的工作状态和存款进度
- python seaborn heatmap可视化相关性矩阵
- VM centos网络配置
- 机器学习基础算法26-聚类理论
- MySQL-快速入门(4)MySQL函数
- MessageBox用法大全
- 7-1 寻找大富翁 (25 分)
- Google浏览器网页,大部分网页出现无法加载样式
- 苹果进入品牌价值衰减期
- 3D 智慧农场可视化——解锁绿色生态田园
- Qt下QTableWidget 基本用法
- 伯克利的电气工程和计算机科学专业,加州大学伯克利分校
- ORACLE单实例ADG搭建
- 戴尔电脑重做win10系统后,耳机故障
- 论文要点总结:Gradient-Based Learning Applied to Document Recognition(一)