如何根据ID将数据框分成训练集、验证集和测试集?

3
我需要将数据集随机分割为训练、验证和测试集,就像这篇文章所示(R: How to split a data frame into training, validation, and test sets?),但需要将分割主题ID与数据框中的其余部分随机关联起来。

当应用该问题的代码时,它完全随机地分割我的数据帧,但我有堆叠的ID,需要它们保持在一起,否则一个科目的数据将分布在不同的集合中。

如果这听起来有点混乱,我很抱歉。以下是我的数据,以解释这个问题:

df <- c(Contact.ID, Date.Time, Age, Gender, Attendance)

Contact.ID       Date.Time       Age   Gender   Attendance   
1   A       2012-07-06 18:54:48   37    Male         30    
2   A       2012-07-06 20:50:18   37    Male         30    
3   A       2012-08-14 20:18:44   37    Male         30   
4   B       2012-03-15 16:58:15   27  Female         40    
5   B       2012-04-18 10:57:02   27  Female         40    
6   B       2012-04-18 17:31:22   27  Female         40    
7   B       2012-04-18 18:37:00   27  Female         40    
8   C       2013-10-22 17:46:07   40    Male         5    
9   C       2013-10-27 11:21:00   40    Male         5    
10  D       2012-07-28 14:48:33   20  Female         12 

如果我随机拆分这些数据,例如,主题A的条目可能在我的测试集中有两个,在验证集中有一个。但我需要不同ID的随机拆分,而不是整个数据框的随机拆分,我无法想出如何连接它们。
1个回答

4

您在之前的训练/验证/测试问题中发布的代码为数据框中的每一行分配了一个训练、验证或测试标签,然后根据每一行的标签进行拆分:

spec = c(train = .6, test = .2, validate = .2)
g = sample(cut(
  seq(nrow(df)), 
  nrow(df)*cumsum(c(0,spec)),
  labels = names(spec)
))
res = split(df, g)

相反,你可以为ID因子变量的每个唯一级别分配一个标签,并基于分配给每行ID的标签进行拆分:

set.seed(144)
spec = c(train = .6, test = .2, validate = .2)
g = sample(cut(
  seq_along(unique(df$Contact.ID)), 
  length(unique(df$Contact.ID))*cumsum(c(0,spec)),
  labels = names(spec)
))
(res = split(df, g[as.factor(df$Contact.ID)]))
# $train
#   Contact.ID          Date.Time Age Gender Attendance
# 1          A 2012-07-0618:54:48  37   Male         30
# 2          A 2012-07-0620:50:18  37   Male         30
# 3          A 2012-08-1420:18:44  37   Male         30
# 8          C 2013-10-2217:46:07  40   Male          5
# 9          C 2013-10-2711:21:00  40   Male          5
# 
# $test
#   Contact.ID          Date.Time Age Gender Attendance
# 4          B 2012-03-1516:58:15  27 Female         40
# 5          B 2012-04-1810:57:02  27 Female         40
# 6          B 2012-04-1817:31:22  27 Female         40
# 7          B 2012-04-1818:37:00  27 Female         40
# 
# $validate
#    Contact.ID          Date.Time Age Gender Attendance
# 10          D 2012-07-2814:48:33  20 Female         12

请注意,这会改变拆分比例的解释:分配给训练集的60%现在是唯一受试者ID的60%,而不是行的60%。

嗨 :) 非常感谢您的回复! 我理解了您的方法以及它应该如何工作,但是它在我的数据上不起作用。我有大约13,000个ID,当我运行您的代码时,它根据spec分割了我的280,000个观测值,但是不同的集合仍然每个有13,000个ID,因此它仍然没有按照spec分割我的ID。您有什么想法可以改变这种情况吗? - Fee
嘿,我想我修好了:我之前把我的ID作为因子变量使用,但现在我尝试将它们改为数值型,我觉得这样行得通。这可能是问题所在吗? - Fee
@Fee,我在这里发布的代码应该适用于ID字段的任何数据类型。如果您在使用时遇到问题,如果能分享一些实际数据,例如dput(head(df))的输出,那将会很有帮助。 - josliber
嗨,是的,我在一个小样本集上尝试了它,并且它确实有效。不同之处在于,当ID是因子时,它会注册所有级别,而如果它是整数,则仅注册当前ID。因此,是的,代码适用于任何变量类型,但是当作为因子使用时会有点混乱。非常感谢您的帮助! :) - Fee
@Fee 是的,那很有道理。 - josliber

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接