在R中工作,我有与下面类似结构的数据(代码块1)。我希望创建一个具有以下特征的新data.frame:
对于每个唯一的ID_1值,我希望有两个新列,一个包含一个列表(ID_2共享ID_1和方向== 1),另一列包含一个列表(ID_2共享ID_1& Direction == 0),(参见下一个代码块2)
数据集块1(初始):
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
转换为:
数据集块2(所需输出):
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" s,这使得这非常耗费时间(小时,我告诉你) !!)。
任何建议 - 也许使用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)
)
我当前(太慢)的代码:
DF2 <- data.frame( ID_1=DF[!duplicated(DF$ID_1),][,1])
for (i in 1:length(unique(DF2$ID_1))){
DF2$ID_2_D1[i] <- list(subset(DF,ID_1==unique(DF2$ID_1)[i] & Direction==1)$ID_2)
DF2$ID_2_D0[i] <- list(subset(DF,ID_1==unique(DF2$ID_1)[i] & Direction==0)$ID_2)
}
答案 0 :(得分:7)
像这样:
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
答案 1 :(得分:4)
@ flodel的答案是迄今为止我能想到的最简单的答案,但这里是使用aggregate
和merge
的基础R中的一个选项。它使用subset
步骤中的“aggregate
”参数来获取“Direction == 0”和“Direction == 1”时的单独列。
temp1 <- aggregate(ID_2 ~ ., DF, as.vector, subset = c(Direction == 0))
temp2 <- aggregate(ID_2 ~ ., DF, as.vector, subset = c(Direction == 1))
merge(temp1[-2], temp2[-2], by = "ID_1", all = TRUE, suffixes=c("_0", "_1"))
# ID_1 ID_2_0 ID_2_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 NULL 4, 44
相关方法(不确定是否会更快)将使用split
在结果列表上创建子集lapply
到aggregate
,并{{1方便Reduce
:
merge
当然,这是使用Reduce(function(x, y)
merge(x, y, by = "ID_1", all = TRUE, suffixes = c("_0", "_1")),
lapply(split(DF[1:2], DF$Direction),
function(x) aggregate(ID_2 ~ ID_1, x, as.vector)))
的一种方法,您可能需要考虑这种方法,因为您已经提到必须在数百万个独特的“ID_1”*上工作*。您不太可能从这个小例子中看到任何速度优势,但您应该使用实际数据。
data.table
正如@Arun在R公共聊天室中提到的,这是一种简化的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.table
答案 2 :(得分:3)
你当然可以在这里使用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," ","
我很想知道这种方式是否/速度有多快。