【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算法进行改进:

  1. 使用无放回抽样得到数据子集。目前传统的Stacking算法是采用五折交叉验证法,将训练数据分成5等份,依次选择其中一份作为验证子集,而其他四份作为训练子集用于模型训练,用训练好的基模型去预测验证子集,预测结果作为第二层的特征。而本文的模型则选择随机不放回抽样,比如连续20次随机抽取80%的样本,组成20个独立的数据子集。

  2. 根据概率随机选取特征。数据集经过数据处理和特征工厂后会产生很多特征,尤其是对离散特征进行独热编码,使得特征空间会变得非常大,而且存在很多冗余特征。因此本文利用GBDT对数据集进行简单训练,并得到各个特征重要性,组成总和为1的概率列表。利用这个概率列表随机选取特征,可过滤冗余特征,构造效率更高、消耗更低的独立的预测模型。

  3. 根据训练集的测试精度进行测试集的权重分配。传统的Stacking算法是采用五折交叉验证法,将数据集划分成五等份,由五组数据子集构成5个基模型,在第一层预测测试集时,取5个基模型的预测结果的平均值作为第二层的特征。这里可能存在数据划分不均,而导致预测效果不佳的情况。因此本文根据基模型的测试精度对预测结果进行加权平均,得到结果作为第二层的特征。

改进Stacking代码

subsample函数是对数据集进行样本与特征的采样,并记录采样情况,因为预测的时候需要对测试集的特征进行相同的采样。
.
改进的算法有三个超参数:

  1. n_tree:基模型个数T
  2. ratio_sample:样本采样比例a
  3. 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算法相关推荐

  1. 高动态环境下基于随机可及集的Path-Guided APF算法的Motion Planning

    文章目录 摘要 引言 相关工作 问题假设 动态障碍物 Relative robot-obstacle dynamics(运动学) SR Sets for Collision Avoidance 方法! ...

  2. 基于随机分形搜索算法的函数寻优算法

    文章目录 一.理论基础 1.随机分形搜索算法 2.SFS算法流程图 二.仿真实验与分析 三.参考文献 一.理论基础 1.随机分形搜索算法 随机分形算法(Stochastic Fractal Searc ...

  3. 【随机共振】基于随机共振的高灵敏度GPS信号捕获算法

    算法结构图 首先input输入到SR 这个语句意思就是每次输入一段数据进行处理,因为这个系统是实时反馈的系统,所以在处理的时候,必须是一段段处理,而不能和原来一样一次性进行处理,所以我们每次处理的数据 ...

  4. 自动驾驶路径规划——基于概率采样的路径规划算法(RRT、RRT*)

    目录 1. RRT算法背景 1.1 RRT算法核心思想 1.2 RRT算法优缺点 2. 经典RRT算法 2.1 RRT算法流程 2.2 RRT伪代码 3. 基于目标概率采样 4. RRT*算法 4.1 ...

  5. PCL 点云分割与分类 Segmentation RANSAC随机采样一致性 平面模型分割 欧氏距离分割 区域聚类分割算法 最小分割算法 超体聚类 渐进式形态学滤波器

    点云分割 博文末尾支持二维码赞赏哦 _ 点云分割是根据空间,几何和纹理等特征对点云进行划分, 使得同一划分内的点云拥有相似的特征,点云的有效分割往往是许多应用的前提, 例如逆向工作,CAD领域对零件的 ...

  6. 机器学习系列|基于随机森林的生存分析模型-R实战

    机器学习系列|基于随机森林的生存分析模型-R实战 随机生存森林 随机生存森林通过训练大量生存树,以表决的形式,从个体树之中加权选举出最终的预测结果. 构建随机生存森林的一般流程为: Ⅰ. 模型通过&q ...

  7. 基于随机无迹σ变异的改进HHO算法

    文章目录 一.理论基础 1.哈里斯鹰优化算法HHO 2.改进哈里斯鹰优化算法OSHHO (1)伪对立和伪反射学习机制 (2)随机无迹点变异机制 (3)能量因子非线性调整机制 (4)OSHHO算法执行流 ...

  8. python随机森林筛选变量_一种基于随机森林的改进特征筛选算法

    刘云翔 陈斌 周子宜 摘  要: 肝癌是一种我国高发的消化系统恶性肿瘤,患者死亡率高,威胁极大.而其预后情况通常只能通过医生的专业知识和经验积累来粗略判断,准确率较差.因此文中在分析随机森林算法的基本 ...

  9. 基于蜣螂算法改进的随机森林回归算法 - 附代码

    基于蜣螂算法改进的随机森林回归算法 - 附代码 文章目录 基于蜣螂算法改进的随机森林回归算法 - 附代码 1.数据集 2.RF模型 3.基于蜣螂算法优化的RF 4.测试结果 5.Matlab代码 6. ...

最新文章

  1. 斯坦福大学马超:探寻「隐式偏差」的完整理论框架
  2. 一句话生成数字人形象、昆仑芯2量产…百度大脑升级7.0,王海峰:技术更强了门槛却更低...
  3. 【vue】介绍一个vuejs 和 element 搭建的一个后台管理界面
  4. qt布局嵌套_PyQt5 笔记(01):嵌套布局
  5. java判断文件或者文件夹
  6. 【励志】公子龙:我的工作状态和存款进度
  7. python seaborn heatmap可视化相关性矩阵
  8. VM centos网络配置
  9. 机器学习基础算法26-聚类理论
  10. MySQL-快速入门(4)MySQL函数
  11. MessageBox用法大全
  12. 7-1 寻找大富翁 (25 分)
  13. Google浏览器网页,大部分网页出现无法加载样式
  14. 苹果进入品牌价值衰减期
  15. 3D 智慧农场可视化——解锁绿色生态田园
  16. Qt下QTableWidget 基本用法
  17. 伯克利的电气工程和计算机科学专业,加州大学伯克利分校
  18. ORACLE单实例ADG搭建
  19. 戴尔电脑重做win10系统后,耳机故障
  20. 论文要点总结:Gradient-Based Learning Applied to Document Recognition(一)

热门文章

  1. 训练神经网络gpu占用率低,gpu为什么适合神经网络
  2. java 监视文件夹下的文件是否发生变化,当发生变时重新获取文件夹里的内容
  3. 远程服务器ip地址可以更改吗,Web远程管理服务器端的IP地址如何进行设置?
  4. war3的mdx动画DEMO
  5. RFID机器人会统治世界吗?
  6. 这是最全的一篇!!!浏览器输入网址后发什么了什么?
  7. 一步步分析百度音乐的播放地址,利用Python爬虫批量下载
  8. 基于PHP房屋租赁管理系统设计与实现
  9. Kubernetes NUMA 感知
  10. 武汉疫情,你还我爱情!