如何将数据集分成多个折叠,同时保持属性的比例固定



假设我有一个具有多个输入特征和一个输出的数据集。为了简单起见,我们假设输出是二进制的。0或1

我想把这个数据集分成k个部分,并使用k-fold交叉验证模型来学习从输入特征到输出特征的映射。如果数据集是不平衡的,输出0的记录数和输出1的记录数之比将不为1。为了使其具体化,假设90%的记录是0,只有10%是1

我认为重要的是,在k-fold的每个部分中,我们应该看到0s和1s的相同比例,以便成功训练(相同的9比1比例)。我知道如何在Pandas中做到这一点,但我的问题是如何在TFX中做到这一点。

阅读TFX文档,我知道我可以通过将output_config指定给加载示例的类来拆分数据集:

output = tfx.proto.Output(
split_config=tfx.proto.SplitConfig(splits=[
tfx.proto.SplitConfig.Split(name='fold_1', hash_buckets=1),
tfx.proto.SplitConfig.Split(name='fold_2', hash_buckets=1),
tfx.proto.SplitConfig.Split(name='fold_3', hash_buckets=1),
tfx.proto.SplitConfig.Split(name='fold_4', hash_buckets=1),
tfx.proto.SplitConfig.Split(name='fold_5', hash_buckets=1)
]))
example_gen = CsvExampleGen(input_base=input_dir, output_config=output)

但是,前面提到的每一叠例子的比例最多是随机的。我的问题是:有没有什么方法可以让我指定每个分割的内容?我是否可以强制执行某个功能的比例?

顺便说一句,我已经看到并试验了SplitConfig类的partition_feature_name参数。除非每个例子都有一个带有折叠ID的特征,否则它在这里是没有用的,我认为这是不实际的,因为我可能想要在不改变数据集的情况下改变折叠次数作为实验的一部分。

我将回答我自己的问题,但只是作为一种变通方法。我很高兴看到有人想出一个真正的解决方案来解决这个问题。

在这一点上,我能想到的是将数据集拆分为许多tfrecord文件。我选择了"复合材料"。所以我可以把它们分成(几乎)任何我想要的数目。对于这一点,我选择了60,因为它可以被2、3、4、5、6、10和12整除(我认为没有人会想要k大于12的KFold)。然后在加载它们的时候,我必须以某种方式选择哪些文件将进入每个分割。这里有两件事需要考虑。

首先,TFX中的ImportExampleGen类支持全局文件模式。这意味着我们可以为每个分割加载多个文件:

input = tfx.proto.Input(splits=[
tfx.proto.Input.Split(name="fold_1", pattern="fold_1*"),
tfx.proto.Input.Split(name="fold_2", pattern="fold_2*")
])
example_gen = tfx.components.ImportExampleGen(input_base=_dataset_folder,
input_config=input)

接下来,我们需要一些聪明才智,以便在加载文件时将文件分割成我们喜欢的任意数量。这是我的方法:

fold_3.0_4.0_5.0_6.0_10.0/part-###.tfrecords.gz
fold_3.0_4.0_5.1_6.0_10.6/part-###.tfrecords.gz
fold_3.0_4.0_5.2_6.0_10.2/part-###.tfrecords.gz
fold_3.0_4.0_5.3_6.0_10.8/part-###.tfrecords.gz
...

文件模式是这样的。在每两个_之间,我包括除数,一个.,然后是余数。我想要多少个就有多少个这样的"分割可能性"稍后,在加载数据集时。

在上面的例子中,我可以选择将它们加载为3,4,5,6和10次。如果我想将数据集分割成任意数量的折叠,第一个文件将作为第0次分割的一部分加载,而第二个文件将在第1次分割的5倍和第6次分割的10倍中加载。

加载方式如下:

NUM_FOLDS = 5
input = tfx.proto.Input(splits=[
tfx.proto.Input.Split(name=f'fold_{index + 1}',
pattern=f"fold_*{str(NUM_FOLDS)+'.'+str(index)}*/*")
for index in range(NUM_FOLDS)
])
example_gen = tfx.components.ImportExampleGen(input_base=_dataset_folder,
input_config=input)

我可以将NUM_FOLDS更改为选项3、4、5、6或10中的任何一个,加载的数据集将由预先规划的k-fold分割组成。值得一提的是,在创建每个文件时,我已经确定了每个文件中样本的比例。所以它们的任何组合也会有相同的比例。

同样,这只是在没有实际解决方案的情况下的一个技巧。这种方法的主要缺点是您必须自己手动拆分数据集。在本例中,我使用了pandas。这意味着我必须将整个数据集加载到内存中。对于所有的数据集,这可能是不可能的。

最新更新