如何确保某个数据点不在分层交叉验证拆分的测试集中?

Posted

技术标签:

【中文标题】如何确保某个数据点不在分层交叉验证拆分的测试集中?【英文标题】:How to ensure a certain datapoint is not in the test set in stratified cross validation split? 【发布时间】:2021-09-14 06:13:04 【问题描述】:

我有一个看起来像这样的 DataFrame。

d = 'col1': [1, 2,3,4,5,6,7,8], 'col2': ['a', 'a','b', 'b', 'c', 'c', 'd', 'd']
df = pd.DataFrame(data=d)
df

  col1  col2
0   1     a
1   2     a
2   3     b
3   4     b
4   5     c
5   6     c
6   7     d
7   8     d

当我使用 k 折交叉验证 时,我想确保 col2 中的值仅存在于训练集或测试集中。也就是说,在拆分过程中,如果df['col2'][0] = adf['col2'][1] = a,那么索引为0 和1 的行都应该在训练集中,否则在测试集中。不应该是第 0 行在训练集中,第 1 行在测试集中。

有没有简单的方法可以做到这一点?

编辑:有没有办法将 DataFrame 分成两部分,这样每个部分都包含在第一个 DataFrame 或第二个 DataFrame 中的 col2 中具有值 a 的所有数据点,但是不是都?我尝试使用groupby,但它返回一个对象,当我将其转换为字典时,我只能通过键访问它,即a, b, c, d

【问题讨论】:

【参考方案1】:

您可以通过执行GroupShuffleSplit 来确保变量值仅存在于集合中,如下所示:

from sklearn.model_selection import GroupShuffleSplit

import pandas as pd

d = 'col1': [1, 2,3,4,5,6,7,8],
    'col2': ['a', 'a','b', 'b', 'c', 'c', 'd', 'd'],
    'label': [1,1,1,1,0,0,0,0]
df = pd.DataFrame(data=d)

X = df[['col1', 'col2']]
y = df['label']
groups= df['col2']
gss = GroupShuffleSplit(n_splits=2, train_size=.8, random_state=42)
for train_idx, test_idx in gss.split(X, y, groups):
    X_train, X_test = X.iloc[train_idx], X.iloc[test_idx]
    y_train, y_test = y.iloc[train_idx], y.iloc[test_idx]

【讨论】:

这太好了,非常感谢。这也会导致训练数据和测试数据之间的分层划分吗?我的标签实际上是第三列。 问题是 sklearn 只提供stratifiedgroup 拆分的可能性。没有分层分组拆分。但你可以自己写。 谢谢,很高兴知道这一点。如果我编写自己的分层组拆分,正确的方法是将其分组,然后检查每个拆分中的标签并仅交换这些行吗?还是有其他方法可以继续? 我将对col2 的唯一值执行分层拆分,然后找到具有这些 col2 值的 X 个样本。但是您不能确定生成的组的大小是否正确。根据 col2 的一个值的表示,结果集可能会有所不同。 似乎sklearn已经在开发阶段here,但是当我尝试使用它时出现导入错误。【参考方案2】:

在@Antoine Dubuis 的帮助下,我找到了我想做的一个 sklearn 实现 - 称为 StratifiedGroupKFold。

截至 2021 年 7 月,它仍在开发中,但可以从开发/夜间版本中使用。我建议创建一个单独的虚拟环境来使用它。

我已经用过,目前看来可以用了,希望能尽快发布稳定版。

【讨论】:

以上是关于如何确保某个数据点不在分层交叉验证拆分的测试集中?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法使用 SKlearn 获得滑动嵌套交叉验证?

如何在 pyspark 上创建分层拆分训练、验证和测试集?

交叉验证如何在学习曲线中发挥作用?蟒蛇学习

交叉验证、留一交叉验证、自助法

scikit-learn 中的分层训练/验证/测试拆分

如何拆分数据进行训练和测试?交叉验证可能吗? M估计还是OLS?