在带有分组约束的 sklearn (python 2.7) 中创建训练、测试和交叉验证数据集?
Posted
技术标签:
【中文标题】在带有分组约束的 sklearn (python 2.7) 中创建训练、测试和交叉验证数据集?【英文标题】:Creating train, test and cross validation datasets in sklearn (python 2.7) with a grouping constraints? 【发布时间】:2013-09-22 18:30:53 【问题描述】:在 Python 中创建训练、测试和交叉验证示例时,我将默认方法视为 -:
1.跳过标题后读取数据集 2. 创建训练、测试和交叉验证样本
import csv
with open('C:/Users/Train/Trainl.csv', 'r') as f1:
next(f1)
reader = csv.reader(f1, delimiter=',')
input_set = []
for row in reader:
input_set.append(row)
import numpy as np
from numpy import genfromtxt
from sklearn import cross_validation
train, intermediate_set = cross_validation.train_test_split(input_set, train_size=0.6, test_size=0.4)
cv, test = cross_validation.train_test_split(intermediate_set, train_size=0.5, test_size=0.5)
我的问题是,我在读取到 numpy 数组的 csv 文件中有一个字段为“A”,并且所有采样都应尊重该字段。也就是说,“A”值相似的所有条目都应该放在一个样本中。
Line #|A | B | C | D
1 |1 |
2 |1 |
3 |1 |
4 |1 |
5 |2 |
6 |2 |
7 |2 |
必填: 第 1、2、3、4 行应放入“一”样本中,第 5、6、7 行应放入“一”样本中。 A 列的值是一个唯一的 id,对应一个实体(可以看作是一个 SINGLE 用户的横截面数据点,因此它必须进入一个唯一的 train、test 或cv),这样的实体很多,所以需要按实体id分组。
B、C、D 列可以有任何值,但不需要对它们进行分组保存。 (奖励:我可以对多个字段的采样进行分组吗?)
我尝试了什么:
A. 找到 A 的所有唯一值 - 将其表示为我的样本我现在将样本分布在 st train、intermediate & cv & test 之间 -> 然后将其余行放入这个“A”值在每个文件中。 也就是说,如果 train 有 "3" 的条目,测试 "2" 和 cv 的 "1",那么所有值为 A 为 3 的行都进入 train,所有 2 进入测试,所有 1 进入 cv。
-
当然,这种方法不可扩展。
我怀疑,它可能会在数据集中引入偏差,因为 A 列中 1 的数量、2 的数量等不相等,这意味着这种方法行不通!
B.我也尝试了 numpy.random.shuffle 或 numpy.random.permutation 根据这里的线程 - Numpy: How to split/partition a dataset (array) into training and test datasets for, e.g., cross validation? ,但它不符合我的要求。
C.第三种选择当然是编写一个自定义函数来进行这种分组,然后根据每组中的数据点数量平衡训练、测试和 cv 数据集。但只是想知道,是否已经有一种有效的方法来实现这一点?
请注意,我的数据集非常庞大,因此理想情况下,我希望有一种确定性的方法来分区我的数据集,而不需要进行多次眼球扫描来确保分区正确。
编辑第 2 部分:
因为我没有找到任何符合我的抽样标准的东西 - 我实际上编写了一个模块来使用分组约束进行抽样。这是它的 github 代码。该代码不是为非常大的数据编写的,因此效率不高。如果您分叉此代码 - 请指出我如何改善运行时。 https://github.com/ekta1007/Sampling-techniques/blob/master/sample_expedia.py
【问题讨论】:
我在 scikit-learn 的序列学习扩展中有一个 function that does roughly this。不过,我不确定它是否适合您的问题。 【参考方案1】:通过强制此类限制,您将向您的程序引入偏见。因此,基于“用户”数据的分区然后收集他们各自的“测量”的方法似乎并不坏。它会很好地扩展,这是O(n)
方法,不扩展的唯一原因是糟糕的实现,而不是糟糕的方法。
现有方法(如 sklearn 库)中没有此类功能的原因是因为它看起来非常人工,并且与机器学习模型的想法背道而驰。如果这些在某种程度上是一个实体,那么它们不应被视为单独的数据点。如果您需要这种单独的表示,那么需要这样的划分,即特定实体不能部分处于测试测试和部分训练中,这肯定会使整个模型产生偏差。
总而言之,您应该从机器学习的角度真正深入分析您的方法是否合理。如果你确定的话,我认为唯一的可能就是自己编写分段,因为即使过去使用了许多 ML 库,我也从未见过这样的功能。
事实上,我不确定,如果将包含 N 个数字(实体大小)的集合分割成 K(=3)个给定总和比例的子集,在处理时是否具有均匀分布作为一个随机过程本身不是NP问题。如果您不能保证均匀分布,那么您的数据集就不能用作训练/测试/验证模型的统计正确方法。即使它有一个合理的多项式解决方案,它仍然可以严重扩展(比线性方法差得多)。如果您的约束是“严格”的,则此疑问适用,如果它们“弱”,您始终可以使用“生成和拒绝”方法,这应该具有摊销的线性复杂度。
【讨论】:
感谢@lejlot - 更具体地说明我的应用程序 - 对于我的用例,我的用户获得了项目推荐列表,因此一个用户有多个条目。 IE。每个用户的确切推荐数量是不同的。我在这里只知道一些条目属于一个用户,这些条目与其他用户不同。我的目标是在现有的推荐列表上做得更好,比如上面的“B”列。除了为测试、训练和 cv 数据集引入这种人为偏差 + 平衡每个数据点的总数之外,还有什么事后的想法吗? 在推荐系统中,您只是像往常一样拆分数据,对实体没有任何限制,应用其他任何东西都没有意义,因为您的系统不仅应该能够预测“空白”的推荐( new) 用户,但也建议现有的新项目,因此它实际上应该以某种方式拆分,即一个用户在所有 train/test/cv 拆分中。如果关于一个用户的知识对于预测另一个用户无用,那么您不应该构建 one 分类器,而是尽可能多地构建用户。无论哪种方式 - 它都与提议的方法相矛盾。【参考方案2】:我也遇到了类似的问题,虽然我的编码不太好,但我想出了下面给出的解决方案:
-
创建了一个仅包含 df 的唯一 ID 的新数据框并删除了重复项。
new = df[["Unique_Id "]].copy()
New_DF = new.drop_duplicates()
-
基于New_DF创建训练和测试集
train, test = train_test_split(New_DF, test_size=0.2)
-
然后将这些训练和测试集与原始 df 合并。
df_Test = pd.merge(df, test, how='inner', on = “Unique_Id”)
df_Train = pd.merge(df, train, how='inner', on = “Unique_Id”)
同样,我们也可以为验证部分创建样本。
干杯。
【讨论】:
以上是关于在带有分组约束的 sklearn (python 2.7) 中创建训练、测试和交叉验证数据集?的主要内容,如果未能解决你的问题,请参考以下文章
带有 SKLEARN、PANDAS 和 NUMPY 问题的 Python 部署包?