再见!交叉验证算法

作为算法工程师,我经常需要快速粗略地估计一个预测模型在给定的数据集上的表现。很长一段时间,我都是通过

交叉验证来这样做的,然而我意识到我完全走偏了。事实上,对于现实世界中的问题,交叉验证是完全不可信

的。

我猜许多算法工程师仍然依赖于这种方法,我认为深入研究这一主题非常重要。

在这篇文章中,我将探讨为什么在处理现实世界的问题时,交叉验证从来都不是一个好的选择,并给出了更好的替代方法。

什么是交叉验证

交叉验证是一种模型验证算法,用于评估在已知数据集上训练的模型在未知数据集的表现。

注意:交叉验证方法包含多种方法,在本文中,为了简单起见,当我们说“交叉验证”时,指的是随机K折叠交

叉验证,这是迄今为止最常见的交叉验证类型。

那么,交叉验证在实践中是如何实现的呢?

假设我们有一个为机器学习模型准备好的数据集,即预测因子矩阵(我们称之为X)和包含目标变量的向量(我们称为y)。

每一行代表一个数据集,交叉验证将数据集的每一行分配给K个折叠中的一个(通常K=5)。请注意,通过确保所有折叠的行数大致相同,可以完全随机地进行分配。

如下图有10行数据集,并设置K=5 ,每行的数字表示分配到第几个折叠数据,如Fold=3,表示分配到第3个折叠的数据集,Fold=2,表示分配到第2个折叠的数据集,绿框表示每行所属的K折,每个折叠的数据集个数相等。

image-20240510214557924

K折交叉验证的原理是在K-1个折叠的数据集上训练模型,并测量其在剩余折叠的数据集性能。

在我们的案例中:

  • 模型A在属于折叠2、3、4和5的所有行进行训练,并对折叠1的行进行预测,然后在折叠1上测量我们

感兴趣的度量(例如精度);

  • 模型B在折叠1、3、4和5上训练,并在折叠2上测量;

  • 模型C在折叠1、2、4和5上训练,并在折叠3上测量;

  • 模型D在折叠1、2、3和5上训练,并在折叠4上测量;

  • 模型E在折叠1、2、3和4上进行训练,并在折叠5上进行测量。

因此我们有5个精度测量值,于是我们取这5个值的平均值,平均值是我们对未知数据集的准确性评估。

你可能会认为:这似乎是一个非常聪明的方法:我们使用所有可用的观测值来验证模型,但从未使用相同的观测值同时训练和验证模型。

那么,可能出了什么问题呢?

交叉验证有什么问题

您可能没有注意到交叉验证背后有一个非常强大的假设,在真实的案例中从未匹配这种假设!

通过完全随机地拆分固定的数据集,每个折叠将具有相同的分布。因此,我们用于训练的K-1折叠的分布将与性能测试中遗漏的折叠非常相似。这会导致我们的交叉验证率非常高,然而评估新数据集的准确率非常低,有相同经历的童鞋么。

原则上,这没有错。如果我们知道新数据集的分布与我们在训练数据上的分布相同,这将很好。问题是在实际应用中,这种情况永远不会发生。

因此我觉得在实践项目开发中,交叉验证就像作弊!

事实上,在现实生活中,总有一些维度(我们称之为分层变量)使新数据与训练数据不同,例如:

  • 时间
  • 空间
  • 商业维度

让我们试着通过一个例子让这种解释变得更加清晰。

假设在不同的城市销售相同的产品,我们想建立一个模型来预测我们的产品在特定城市以特定的销售价格是否

会被购买。

如下图,我们有两个特征:城市和售价

image-20240510220829584

San Francisco(旧金山)的售价比 Cincinnati(辛辛那提)贵,通过上图的数据,我们设置旧金山的售价阈值是95美元,辛辛那提的售价阈值是85美元,意味着当旧金山产品的价格低于95美元,消费者才会购买,辛辛那提低于85美元时,消费者才会购买。

现在让我们使用交叉验证来计算模型的准确性。出于简单起见,让我们使用2折叠(K=2)。

image-20240512180052989

如上图的随机抽样,折叠1和折叠2的分布完全相同。毕竟,这是交叉验证的重要假设。由于拆分是完全随机的,我们期待每次的折叠都遵循相同的分布。

现在,让我们看看在训练/测试阶段会发生什么。

模型A在折叠1数据进行训练,由于折叠2和折叠1完全相等,当我们使用模型A对折叠2进行预测时,我们得到了完美的预测,准确率100%。

同样地,我们在折叠2数据训练模型B,并在折叠1的数据进行测试时,准确率100%。

image-20240512181320476

当然,这个例子的拆分是故意的。但主要观点是,交叉验证的不同fold之间总会存在一些“信息泄露”。

请注意,在实际情况中,即使我们没有在训练数据集中包含分层变量,数据集中可能会有许多其他特征,因此模型可能会找到其他捷径来“作弊”,即通过识别数据集中的其他特征来识别城市(不可观察)。

那么在实际预测时会发生什么?

根据交叉验证方法的最后一个步骤,我们在整个数据集(所有12行)上训练一个新模型,并使用它对一些新数据进行预测。

例如,假设我们想要在一个新的城市纽约使用这个模型。纽约的价格更类似于旧金山而不是辛辛那提,所以我们假设“阈值价格”为100美元。但模型无法知道这一点,因为纽约没有出现在训练数据集中。

因此,在纽约的预测结果:

image-20240512181914838

预测准确率只有75%,远远低于交叉验证的100%准确率。

一种比交叉验证更好的替代方法

由于交叉验证存在过度乐观的问题,我们需要一种更为真实的数据拆分策略,这种真实体现在更符合真实的数据集分布。

如上述例子,我们希望将模型应用于一个新的城市,我们优化数据集划分策略,每个城市只出现在一个fold中。这被称为组K折(group K-fold)交叉验证。通过这样做,我们确保不同fold之间没有信息泄漏:每个城市要么在训练集中,要么在测试集中。通俗地讲,不同组的数据集分布是完全不一样的,不存在信息泄漏。

因此2折交叉验证就有如下图的划分:

image-20240512182959862

模型A在折叠1数据集训练,得到售价阈值是95,因此训练准确率100%。将模型A应用在折叠2数据集,得到验证准确率是67%。

模型B在折叠2数据集训练,得到售价阈值是85,因此训练准确率100%。将模型B应用在折叠1数据集,得到验证准确率是67%。

这种组K折交叉验证更接近于实际情况(75%),而不是100%(交叉验证),因此组K折交叉验证是一种比交叉验证更好的估计方法。

这只是一个很简单的举例,让我们看看同样的情况是否适用于真实数据集。

真实数据集的验证

我们通过Pycaret库获取“银行”数据集。

from pycaret.datasets import get_data
data = get_data('bank')

通过该数据集比较组K交叉验证和K折交叉验证。

该数据集包含银行客户的信息,具体包括:

  • 个人信息(年龄、职业、婚姻状况、教育水平)
  • 账户信息(账户余额、是否存在信用违约、是否有房屋贷款、是否有个人贷款)
  • 营销信息(通讯方式、最近的一次联系是星期几、几月份以及持续时间、同一营销活动期间的联系次数等信息)

可视化前5个数据集的特征信息:

image-20240512185106913

我们预测模型的目标是预测产品(银行定期存款)是否会被订阅(1)或不会被订阅(0)。

我们使用月份作为分层变量,如下图每个月累积的客户数(如1月1403,2月2649):

image-20240512185734758

为了模拟真实环境中的情况,让我们选择一个特定的月份(例如二月),并将其用作“未见过的月份”。

换句话说,假设我们处于一月底,我们想要在过去的11个月(三月到一月)上构建一个模型,并将其用于仍未观察到的二月数据。

我们对比交叉验证和组 K 折交叉验证。

在交叉验证中,拆分是随机的,因此在每个折叠数据中,我们将拥有属于所有 11 个月的行。Scikit-learn 使用这种拆分策略进行交叉验证:

from sklearn.model_selection import cross_val_score

cross_val_score(estimator=model, X=X, y=y)

在组 K 折交叉验证中,每个月只允许出现在一个折叠中。在 Scikit-learn 中,我们可以使用以下代码进行这种类型的验证

from sklearn.moddel_selection import cross_val_score, GroupKFold

cross_val_score(estimator=model, X=X, y=y, cv=GroupKFold(), groups=X["month"])

因此,每个月所属不同的折叠数据集。

image-20240512191725820

由于每个月的行数非常不平衡,而我们选择了 K=5,因此组 K 折交叉验证尽最大努力使 5 个折叠的大小尽可能相等。例如,拥有最多行数的五月份,会被分在一个独立的折叠中。

根据交叉验证模型优化步骤:

  • 在数据集(除了二月)上运行了 5 折交叉验证;

  • 在数据集(除了二月)上运行了 5 折组 K 折交叉验证;

  • 在 11 个月(三月到一月)上训练了一个模型,并在二月的数据集上测量其性能 - 这是我们的基准

为了使结果更加健壮,我已经针对不同的模型重复了这个过程:随机森林(random forest)、XGBoost 和 LightGBM。如下图,灰色圆圈表示交叉验证,蓝色圆圈表示组K折交叉验证,红色倒三角形是在新数据集上的测试。

结果对比:

解释上述图表:

  • 灰色点:交叉验证中每个折叠观察到的平均精度;
  • 灰色条:5 个灰色点的简单平均 — 即交叉验证提供的最终估计;
  • 蓝色点:组 K 折交叉验证中每个折叠观察到的平均精度 — 即组 K 折交叉验证提供的最终估计;
  • 蓝色条:5 个蓝色点的简单平均;
  • 倒红色三角形:在新数据集的测试精度(金标准)

通过上述图表,我们很容易得到蓝色条更接近倒红色三角形,因此组K折交叉验证的准确率更客观些。

结论

通过上述例子,表明为什么在现实生活中使用交叉验证来估计模型性能可能会完全误导人。

表现在:

  • 验证模型的准确会远远高于实际的表现
  • 模型易过拟合

组K交叉验证的评价更具客观性且预测的方差较小。

欢迎扫码关注:

相关推荐

  • 每日 prompt:皮克斯风格女性
  • ChatGPT 又上新了!听、看、说的综合能力干翻所有语音助手?
  • 14 个 SpringBoot 优化小妙招,写代码像写诗
  • 为什么要将Modbus转成MQTT?
  • 7.6K Star这是抖音APP开源了???
  • 大模型RAG入门及实践
  • Transformer已死?Mamba强的离谱!
  • 一图读懂Linux文件路径
  • LFOSSA源来如此公开课 | 深入理解Kubernetes Pod资源对象
  • 某开源公司前员工爆料:技术leader被下属挑战后狂怒爆粗、辞退怀孕女员工
  • 拾日谈:接下来要活着、健康地活着、有点理想地活着
  • 再次更新!聚合六大平台,功能十分强大!
  • 又一巨头猛裁员,赔偿方案比特斯拉还香!
  • 开源 APM 和可观察性工具 Coroot 现已正式发布
  • 「腾云之路」首期丨更高效能来自更优选择,贝壳降本增效有何高招?| Q推荐
  • Shopee 海量商品系统的治理挑战和应对之策
  • OpenAI 官宣旗舰模型 GPT-4o,完全免费、无障碍与人交谈!奥特曼:这是我们最好的模型
  • 可复用的“企业AI人才梯队搭建”方法论:《数智时代的AI人才粮仓模型解读白皮书(2024版)》发布!| 极客邦科技双数研究院
  • 金融风控姐妹篇-互联网风控的技术成熟度曲线发布!
  • 弄懂标签中台:数据流转与架构揭秘