一、K折交叉验证训练单个模型

1.1 k 折交叉验证(K-Fold Cross Validation)原理

通过对 k 个不同分组训练的结果进行平均来减少方差,因此模型的性能对数据的划分就不那么敏感,经过多次划分数据集,大大降低了结果的偶然性,从而提高了模型的准确性。具体做法如下:

  • step1:不重复抽样将原始数据随机分为 k 份。
  • step2:每一次挑选其中 1 份作为验证集,剩余 k-1 份作为训练集用于模型训练。一共训练k个模型。
  • step3:在每个训练集上训练后得到一个模型,用这个模型在测试集上测试,计算并保存模型的评估指标,
  • step4:计算 k 组测试结果的平均值作为模型最终在测试集上的预测值,求k 个模型评估指标的平均值,并作为当前 k 折交叉验证下模型的性能指标。

要注意的是:
(1)K折交叉验证适合大样本的数据集,在小样本数据集上就很难识别数据中的趋势,导致错误产生。
(2)K折交叉验证不适合包含不同类别的数据集。比如:若数据集有5类数据(ABCDE各占20%),抽取出来的也正好是按照类别划分的5类,第一折全是A,第二折全是B……这样划分的数据集建立的模型显然没什么意义。第一折训练的模型把样本全判为A、第二折训练的模型把样本全判为B…这种情况下,可以使用分层交叉验证 (Stratified k-fold cross validation)。sklearn.model_selection中有相关函数可以调用。StratifiedKFold

from sklearn.model_selection import StratifiedKFold
skf = StratifiedKFold(n_splits=5,shuffle=False,random_state=0)

(3)如果训练集不能很好地代表整个样本总体,分层交叉验证就没有意义了。这时候,可以使用重复交叉验证,即每次用不同的划分方式划分数据集,每次划分完后的其他步骤和K折交叉验证一样。(重复K折交叉验证可以提高模型评估的精确度,同时保持较小的偏差。)
下面这段代码就是重复两次划分数据集(n_repeats=2),每次数据集都进行5折交叉验证(n_splits=5)。

kf = RepeatedKFold(n_splits=5, n_repeats=2, random_state=None)

1.2 代码

下面将交叉验证过程与模型训练过程融合在一起,编写成一个可以自动化处理的函数,可以保存为py文件,建模的时候直接调用。该函数需要输入训练集X,测试集X_test、训练集对应的标签列y,模型的最优参数组合字典params,还有已经划分好的K折样本folds,还有模型类型model_type(3个选择:LightGBM、Xgboost、Catboost,都是Kaggle中很常用的模型,如果想加入其他的可选择模型,在代码中再多增加一个if判断就可以)、决定是回归问题还是分类问题的eval_type。输出的是交叉验证中过程中几个小模型在训练集上得出的预测值oof(保存好之后可以用于stacking融合),几个小模型在测试集上的平均预测 predictions, 模型评估指标scores(回归问题用RMSE、分类问题用logloss)

def train_model(X, X_test, y, params, folds, model_type='lgb', eval_type='regression'):#生成一个和训练集样本量一样大的空数列,用来存放交叉验证中的小模型在训练集上的预测值,以后会在stacking中用到这些数据oof = np.zeros(X.shape[0])#存放测试集的预测结果predictions = np.zeros(X_test.shape[0])#scores = []#enumerate(folds.split(X, y))返回第i折的测试集索引trn_idx、验证集索引val_idxfor fold_n, (trn_idx, val_idx) in enumerate(folds.split(X, y)):print('Fold', fold_n, 'started at', time.ctime())if model_type == 'lgb':#lightgbm要封装数据trn_data = lgb.Dataset(X[trn_idx], y[trn_idx])val_data = lgb.Dataset(X[val_idx], y[val_idx])#实例化一个lightgbm模型clf,在第i折的训练集上训练模型clf = lgb.train(params, trn_data, num_boost_round=20000, valid_sets=[trn_data, val_data], verbose_eval=100, early_stopping_rounds=300)#实例化后的模型clf在第i折的验证集上预测,并按照索引放在空数列里面,以后的stacking过程中会用到。oof[val_idx] = clf.predict(X[val_idx], num_iteration=clf.best_iteration)#在测试集上预测,将预测值除以折数,因为最终的模型预测值输出的是几个小模型预测值的平均值。predictions += clf.predict(X_test, num_iteration=clf.best_iteration) / folds.n_splitsif model_type == 'xgb':trn_data = xgb.DMatrix(X[trn_idx], y[trn_idx])val_data = xgb.DMatrix(X[val_idx], y[val_idx])watchlist = [(trn_data, 'train'), (val_data, 'valid_data')]clf = xgb.train(dtrain=trn_data, num_boost_round=20000, evals=watchlist, early_stopping_rounds=200, verbose_eval=100, params=params)oof[val_idx] = clf.predict(xgb.DMatrix(X[val_idx]), ntree_limit=clf.best_ntree_limit)predictions += clf.predict(xgb.DMatrix(X_test), ntree_limit=clf.best_ntree_limit) / folds.n_splitsif (model_type == 'cat') and (eval_type == 'regression'):clf = CatBoostRegressor(iterations=20000, eval_metric='RMSE', **params)clf.fit(X[trn_idx], y[trn_idx], eval_set=(X[val_idx], y[val_idx]),cat_features=[], use_best_model=True, verbose=100)oof[val_idx] = clf.predict(X[val_idx])predictions += clf.predict(X_test) / folds.n_splitsif (model_type == 'cat') and (eval_type == 'binary'):clf = CatBoostClassifier(iterations=20000, eval_metric='Logloss', **params)clf.fit(X[trn_idx], y[trn_idx], eval_set=(X[val_idx], y[val_idx]),cat_features=[], use_best_model=True, verbose=100)oof[val_idx] = clf.predict_proba(X[val_idx])[:,1]predictions += clf.predict_proba(X_test)[:,1] / folds.n_splitsprint(predictions)if eval_type == 'regression':scores.append(mean_squared_error(oof[val_idx], y[val_idx])**0.5)if eval_type == 'binary':scores.append(log_loss(y[val_idx], oof[val_idx]))print('CV mean score: {0:.4f}, std: {1:.4f}.'.format(np.mean(scores), np.std(scores)))return oof, predictions, scores

二、多模型融合

Kaggle比赛中常常会融合多个模型来提升性能。模型融合的好处在于:

  • 单个模型容易导致泛化能力不佳,多个模型融合可以提升泛化能力
  • 使用单个模型时,有些算法容易陷入局部极小,有的局部极小点对应的泛化能力较差,使用多个模型多次计算,可以降低陷入局部极小点的风险。
  • 使用单个模型时,有时学习任务真实的假设空间和当前模型考虑的假设空间不一样,这时候相当于白学;但使用多个模型,就能扩大假设空间,能够取得更好的近似。[1]

常用的模型融合有以下几种方式:投票融合法、平均融合法、加权融合法、排序融合法、stacking融合。其中投票法在分类问题中比较常用;平均融合法是一种特殊的加权融合方法,这两种方法在回归问题中较常见;排序融合常用于评估指标是排序或者与阈值相关的情况;stacking方法对于回归问题、分类问题都适用。
下面解释几个常用的模型融合方法。

2.1 平均融合法

简单粗暴,训练好了n个模型,就直接将n个模型的预测值求平均值。比如三个模型分别是:Catboost、Xgboost、LightGBM,注意在之前训练模型的时候,就把这三个模型在测试集上面的prediction保存下来,相加求平均就好。

prediction_end=(predictions_lgb + predictions_xgb + predictions_cat) / 3

2.2 加权融合

还是上面的三个模型,单独训练的时候,就把它们的评估指标(比如RMSE)保存好,表现好的模型,就把它的模型权重调大一些。由于RMSE是越小越好,权重大小就与RMSE大小成反比,权重设置可以是:

w1=(1/RMSE_Xgb)/(1/RMSE_Xgb+1/RMSE_Cat+1/RMSE_Lgb)
w2=(1/RMSE_Cat)/(1/RMSE_Xgb+1/RMSE_Cat+1/RMSE_Lgb)
w3=(1/RMSE_Lgb)/(1/RMSE_Xgb+1/RMSE_Cat+1/RMSE_Lgb)prediction_end=w1*predictions_lgb + w2*predictions_xgb + w3*predictions_cat

值得注意的是,加权融合法未必优于平均融合法。因为加权融合法中的权重往往是从数据中学习到的,比如上面我们用的权重,就是先再数据上建模计算出RMSE,再用RMSE的倒数来计算权重,换一份数据集可能这个权重会变了,因为往往训练样本中都有噪声,或者样本不完全。一般而言,模型之间性能相差较大时,用加权融合法,模型之间性能相近,用平均融合法

2.3 stacking融合

stacking是一种集成思想,很多集成算法都是它的变体。准确地来讲,stacking方法是用“学习”的方法来融合模型(对比一下加权融合、平均融合,这两种是用一个规则、一个公式来融合几个模型的预测结果),也就是把要融合的几个模型的预测结果,通过另外一个学习模型融合起来。这个用于融合的学习模型被称为元学习器(meta-learner),而几个单模型都是初级学习器。
satcking融合的步骤:

  • step1:训练T个初级学习器,要使用交叉验证的方法在Train Set上面训练(因为第二阶段建立元学习器的数据是初级学习器输出的,如果初级学习器的泛化能力低下,元学习器也会过拟合)
  • step2:T个初级学习器在Train Set上输出的预测值,作为元学习器的训练数据D,有T个初级学习器,D中就有T个特征。D的label和训练初级学习器时的label一致。
  • step3:T个初级学习器在Test Set上输出的预测值,作为训练元学习器时的测试集,同样也是有T个模型就有T个特征。
  • step4:训练元学习器,元学习器训练集D的label和训练初级学习器时的label一致。

上面这几个步骤就是最普通的stacking的一般步骤。整个流程如下图所示。
上图中第一层就是用5折交叉验证来训练初级学习器,训练了3个初级学习器。第二层就是在训练元学习器,这时的训练集有3个特征。

其实在第二层训练元学习器的时候,也可以再利用交叉验证的思想,来提高元学习器在测试集上的预测能力。

下面是stacking融合的代码,可以保存成py文件,直接调用。

def stack_model(oof_1, oof_2, oof_3, predictions_1, predictions_2, predictions_3, y, eval_type='regression'):# Part 1.数据准备# 按行拼接列,拼接验证集所有预测结果# train_stack就是final model的训练数据train_stack = np.hstack([oof_1, oof_2, oof_3])# 按行拼接列,拼接测试集上所有预测结果# test_stack就是final model的测试数据test_stack = np.hstack([predictions_1, predictions_2, predictions_3])# 创建一个和验证集行数相同的全零数组,oof = np.zeros(train_stack.shape[0])# 创建一个和测试集行数相同的全零数组predictions = np.zeros(test_stack.shape[0])# Part 2.多轮交叉验证(对于stacking第二步骤的交叉验证):划分为5折,每一折训练集上面用贝叶斯回归来训练模型(模型融合过程)#在验证集上from sklearn.model_selection import RepeatedKFoldfolds = RepeatedKFold(n_splits=5, n_repeats=2, random_state=2020)# fold_为折数,trn_idx为每一折训练集index,val_idx为每一折验证集indexfor fold_, (trn_idx, val_idx) in enumerate(folds.split(train_stack, y)):# 打印折数信息print("fold n°{}".format(fold_+1))# 训练集中划分为训练集的样本和标签trn_data, trn_y = train_stack[trn_idx], y[trn_idx]# 训练集中划分为验证集的样本和标签val_data, val_y = train_stack[val_idx], y[val_idx]# 开始训练时提示print("-" * 10 + "Stacking " + str(fold_+1) + "-" * 10)# 采用贝叶斯回归作为结果融合的模型(final model)clf = BayesianRidge()# 在训练数据上进行训练clf.fit(trn_data, trn_y)# 在验证数据上进行预测,并将结果记录在oof对应位置(用来计算评估指标)oof[val_idx] = clf.predict(val_data)# 对测试集数据进行预测,每一轮预测结果占比额外的1/10(多轮交叉验证:n_splits=5, n_repeats=2)predictions += clf.predict(test_stack) / (5 * 2)if eval_type == 'regression':print('mean: ',np.sqrt(mean_squared_error(y, oof)))if eval_type == 'binary':print('mean: ',log_loss(y, oof))# 返回测试集的预测结果return oof, predictions

[1]《机器学习》周志华

Kaggle上分技巧——单模K折交叉验证训练+多模型融合相关推荐

  1. ML:模型训练/模型评估中常用的两种方法代码实现(留一法一次性切分训练和K折交叉验证训练)

    ML:模型训练/模型评估中常用的两种方法代码实现(留一法一次性切分训练和K折交叉验证训练) 目录 模型训练评估中常用的两种方法代码实现 T1.留一法一次性切分训练 T2.K折交叉验证训 模型训练评估中 ...

  2. 在Mnist数据上使用k折交叉验证训练,pytorch代码到底怎么写

    前言 最近学到了K折交叉验证,已经迫不及待去实验一下他的效果是不是如老师讲的一样好,特此写下本文. 本文运行环境为:sklearn.pytorch .jupyter notebook k折交叉验证介绍 ...

  3. 【Kaggle比赛常用trick】K折交叉验证、TTA

    一.什么是k折交叉验证? 在训练阶段,我们一般不会使用全部的数据进行训练,而是采用交叉验证的方式来训练.交叉验证(Cross Validation,CV)是机器学习模型的重要环节之一.它可以增强随机性 ...

  4. 机器学习基础|K折交叉验证与超参数搜索

    文章目录 交叉验证 交叉验证的概念 K的取值 为什么要用K折交叉验证 Sklearn交叉验证API 超参数搜索 超参数的概念 超参数搜索的概念 超参数搜索的原理 Sklearn超参数搜索API 实例 ...

  5. 学习笔记5-梯度爆炸和梯度消失(K折交叉验证)

    1.梯度消失.梯度爆炸 梯度消失和梯度爆炸 考虑到环境因素的其他问题 1.1 本次课程主要任务 了解学习梯度消失与梯度爆炸产生的原因以及怎么样解决. 考虑到环境因素的其他问题(协变量偏移,标签偏移,概 ...

  6. 机器学习(MACHINE LEARNING)交叉验证(简单交叉验证、k折交叉验证、留一法)

    文章目录 1 简单的交叉验证 2 k折交叉验证 k-fold cross validation 3 留一法 leave-one-out cross validation 针对经验风险最小化算法的过拟合 ...

  7. matlab-K折交叉验证与分层K折交叉验证

    文章目录 K折交叉验证有什么用? 如何实现K折交叉验证? K折交叉验证的要点:(文字版) 如何实现K折交叉验证(图片版) 如何实现K折交叉验证(matlab版) 为啥我们需要分层K折交叉验证? 如何实 ...

  8. 交叉验证(简单交叉验证、k折交叉验证、留一法)

    针对经验风险最小化算法的过拟合的问题,给出交叉验证的方法,这个方法在做分类问题时很常用: 一:简单的交叉验证的步骤如下: 1. 从全部的训练数据 S中随机选择 中随机选择 s的样例作为训练集 trai ...

  9. 交叉验证的几个方法的解释(简单交叉验证、k折交叉验证、留一法)

    针对经验风险最小化算法的过拟合的问题,给出交叉验证的方法,这个方法在做分类问题时很常用: 一:简单的交叉验证的步骤如下: 1. 从全部的训练数据 S中随机选择 中随机选择 s的样例作为训练集 trai ...

最新文章

  1. MySQL 索引与优化
  2. 使用GDAL创建Erdas格式的金字塔
  3. 集众家之所长,你工作中遇到的可视化问题,如何在 Tableau 官网提交 Case?
  4. case when else 默认随机_SQL高级知识——CASE的用法
  5. 简单区分Vmware的三种网络连接模式(bridged、NAT、host-only)
  6. 计算机基础及msoffice应用好考吗,全国计算机等级考试考试一级WPS Office和MS Office有什么不同?那个好考?...
  7. 在O(1)的时间内计算n个整数落在区间[a,b]的个数(预处理时间为O(n+k))
  8. Java 9:Process API的增强
  9. python request 留位置4
  10. java怎么获取当前日期_JAVA中获取当前系统时间
  11. gradle和maven区别
  12. 如何在React Native中使用React JS Hooks?
  13. 吴恩达机器学习笔记十四之大规模机器学习
  14. vb中findwindow的疑惑
  15. MyBatis #{ } ${ }
  16. 产品经理,设计师,前端工程师必备的绘图工具(原型图,思维导图,UML,流程图,架构图)
  17. 基于SSM框架实现的日记管理系统
  18. 2021年我国热泵市场规模、产值及进出口分析[图]
  19. itunes cannot read the contents of the iphone
  20. DPI、像素与分辨率的区别和联系

热门文章

  1. The following error occurred while installing.This is a fatal error andinstallation will be aborted.
  2. SpringCloud 微服务架构开源项目,适合接私活、毕业设计(附源码)
  3. mysql 分位数 知乎_分位数的意义是什么?
  4. PHP短信通知+语音播报自动双呼
  5. 英国诺丁汉大学的AIMS与虚拟现实技术
  6. 浙江电信IPTV+上网 Padavan老毛子固件单线复用
  7. Servlet - Sessions and Cookies
  8. Linux中source filename .(点)filename ./filename sh filename的区别
  9. 8051单片机Proteus仿真与开发实例-OLED显示屏(SSD1306控制器)I2C驱动显示中文及图片仿真
  10. STM32外部中断的关闭和打开