R 基于较大数据帧的多个子集创建多个列表
在R中工作时,我的数据结构与下面类似(代码块1)。我希望创建一个具有以下特征的新data.frame: 对于每个唯一的ID_1值,我希望有两个新列,一个包含(共享ID_1&Direction==1的ID_2)列表,另一个列包含(共享ID_1&Direction==0的ID_2)列表(见下一个代码块2) 数据集块1(首字母):R 基于较大数据帧的多个子集创建多个列表,r,subset,plyr,R,Subset,Plyr,在R中工作时,我的数据结构与下面类似(代码块1)。我希望创建一个具有以下特征的新data.frame: 对于每个唯一的ID_1值,我希望有两个新列,一个包含(共享ID_1&Direction==1的ID_2)列表,另一个列包含(共享ID_1&Direction==0的ID_2)列表(见下一个代码块2) 数据集块1(首字母): ID_1 ID_2 Direction 100001 1 1 100001 11 1 100001 111
ID_1 ID_2 Direction
100001 1 1
100001 11 1
100001 111 1
100001 1111 0
100001 11111 0
100001 111111 0
100002 2 1
100002 22 1
100002 222 0
100002 2222 0
100003 3 1
100003 33 1
100003 333 1
100003 3333 0
100003 33333 0
100003 333333 1
100004 4 1
100004 44 1
ID_1 ID_2_D1 ID_2_D0
100001 1,11,111 1111,11111,111111
100002 2,22 222,222
100003 3,33,333,333333 3333,33333
100004 4,44
转换为:
数据集块2(所需输出):
ID_1 ID_2 Direction
100001 1 1
100001 11 1
100001 111 1
100001 1111 0
100001 11111 0
100001 111111 0
100002 2 1
100002 22 1
100002 222 0
100002 2222 0
100003 3 1
100003 33 1
100003 333 1
100003 3333 0
100003 33333 0
100003 333333 1
100004 4 1
100004 44 1
ID_1 ID_2_D1 ID_2_D0
100001 1,11,111 1111,11111,111111
100002 2,22 222,222
100003 3,33,333,333333 3333,33333
100004 4,44
我有这样做的代码(对子集的子集进行循环),但我在数百万个唯一的“ID_1”上运行它,这非常耗时(我告诉你,几个小时!)
有什么建议吗?也许使用apply()或plyr()包可以让它运行得更快
参考代码:
DF <- data.frame(ID_1=c(100001,100001,100001,100001,100001,100001,100002,100002,100002,100002,100003,100003,100003,100003,100003,100003,100004,100004)
,ID_2=c(1,11,111,1111,11111,111111,2,22,222,2222,3,33,333,3333,33333,333333,4,44)
,Direction=c(1,1,1,0,0,0,1,1,0,0,1,1,1,0,0,1,1,1)
)
DF您当然可以在这里使用apply函数。我不确定你是否需要,(也就是说,你可以通过子集变得更快),但我想不出你现在会怎么做。你可以像这样实现你想要的:
# Direction = 1
d1 <- lapply( unique( DF$ID_1 ) , function(x){ subset( DF , ID_1== x & Direction == 1)$ID_2 } )
d1 <- sapply( d1 , function(x){ paste0( x , sep = "," , collapse = "" ) } )
# Direction = 0
d0 <- lapply( unique( DF$ID_1 ) , function(x){ subset( DF , ID_1== x & Direction == 0)$ID_2 } )
d0 <- sapply( d0 , function(x){ paste0( x , sep = "," , collapse = "" ) } )
# Results dataframe
resDF <- data.frame(ID_1 = unique(DF$ID_1), d1, d0)
resDF
d1 d0
[1,] "100001" "1,11,111," "1111,11111,111111,"
[2,] "100002" "2,22," "222,2222,"
[3,] "100003" "3,33,333,333333," "3333,33333,"
[4,] "100004" "4,44," ","
#方向=1
d1像这样:
library(reshape2)
dcast(DF, ID_1 ~ Direction, value.var = "ID_2", list)
# ID_1 0 1
# 1 100001 1111, 11111, 111111 1, 11, 111
# 2 100002 222, 2222 2, 22
# 3 100003 3333, 33333 3, 33, 333, 333333
# 4 100004 4, 44
@flodel的答案是迄今为止我能想到的最直接的答案,但在BaseR中有一个选项,使用aggregate
和merge
。它利用aggregate
步骤中的“subset
”参数获取“Direction==0”和“Direction==1”时的单独列
当然,这里有一个使用<代码>数据>表< /> >的方法,您可能需要考虑,正如您所提到的,必须处理超过几百万个唯一的“ID1”S*。您不太可能从这个小示例中看到任何速度优势,但您应该使用实际数据
library(data.table)
DT <- data.table(DF, key = "ID_1")
DT0 <- DT[Direction == 0, list(D0 = list(ID_2)), by = key(DT)]
DT1 <- DT[Direction == 1, list(D1 = list(ID_2)), by = key(DT)]
DT0[DT1]
# ID_1 D0 D1
# 1: 100001 1111,11111,111111 1,11,111
# 2: 100002 222,2222 2,22
# 3: 100003 3333,33333 3,33,333,333333
# 4: 100004 4,44
这在一个小数据集上执行得非常好。我想知道它的伸缩性有多好?我希望最后一步类似于data.frame(ID_1=unique(DF$ID_1),d1,d0)
而不是cbind(…)
+1按照您的建议进行编辑!是的,这个解决方案可能不是最好的。事实上,与弗洛德尔超优雅的一款衬里相比,它看起来确实有些过时。然而,dcast
和cast
确实在内部使用了许多apply函数族。不过,我无法估计有多少实际工作是由dcast
中的apply
函数完成的。您的代码非常有用(但我很快就发现flodel的建议)。谢谢大家!@SimonO101,我忘了在前面提到一件事:我对你的答案的一个批评是,用这种方法你实际上只得到一个字符串。其他方法将值保持为向量的列表
,因此,如果需要,可以轻松地进一步处理该数据。尽管如此,看到替代方案并获得更多想法还是很棒的!我的上帝。通过测试我的完整数据的一小部分,我的代码(在上面的原始帖子中)在20多小时内完成了完整数据集的测试(因此,我的帖子)。你的代码在5秒内完成了--我想我能分辨出一个好的程序员和我自己之间的区别。谢谢你为我节省了很多时间@出于兴趣的经济法庭什么方法最快?我假设这是一个,但它看起来像是dcast
正在使用lappy
和表兄妹,所以我想知道它是否更快?如果此解决方案对您有效,请务必勾选解决方案顶部旁边的绿色箭头,以便将此问题标记为已回答。对于你们来说,这是一个愚蠢的问题——但好奇的是,您是否可以告诉我(或者,给我一个指向维基百科文章或cran文档的链接),为什么dcast比我的循环快得多--我在数百万行上完成了这项工作,dcast在17秒内完成了这项工作(加上一点额外的子集和合并),正如我所说的,我的方法在一天内完成。(只是想了解基本理论)和@SimonO101——在我的数据上(忽略所有额外需要的子集和合并位:)(1)flodel的dcast:7.4秒,(2)Ananda Mahto的聚合在同一个任务上花费了23秒,(3)Arun的补充:我真的无法运行,抱歉,(4)我的循环被记录在190小时内完成(我记录了0.01%的子集,耗时68秒)。+1一组非常好的解决方案。我喜欢这个问题,所以我可以检查你的参考答案。
library(data.table)
DT <- data.table(DF, key = "ID_1")
DT0 <- DT[Direction == 0, list(D0 = list(ID_2)), by = key(DT)]
DT1 <- DT[Direction == 1, list(D1 = list(ID_2)), by = key(DT)]
DT0[DT1]
# ID_1 D0 D1
# 1: 100001 1111,11111,111111 1,11,111
# 2: 100002 222,2222 2,22
# 3: 100003 3333,33333 3,33,333,333333
# 4: 100004 4,44
DT[, list(list(D0 = ID_2[Direction==0]), list(D1 = ID_2[Direction == 1])), by=ID_1]