R 数据表用户定义的函数很慢



我有两个数据表dt1dt2dt1ii的各个指标列表和时间指标列表tt构成。 具有 3 个个体和两个时间段的示例是:

library(data.table)
ii_ind = c(1,2,3)
tt_ind = c(2010,2011)
dt1 = merge(x=data.frame(ii =ii_ind) , y = data.frame(jj=ii_ind))
dt1 = merge(x=dt1 , y = data.frame(tt = tt_ind))
dt1 = as.data.table(dt1)
dt1 = dt1[ii != jj]

dt1表示动态网络中的二元组(边缘指示器在第四列中,但与我在这里尝试执行的操作无关)。

dt2有三列分别表示ii、时间tt,以及一个整数变量zz。 例如:

dt2 = data.table(ii = c(1,1,1,1,1,2,2,2,2,3,3), 
tt = c(2010,2010,2011,2011,2011,2010,2010,2011,2011,2010,2011),
zz = c(1,2,1,2,3,1,2,1,2,3,3))

我想要dt1中的新列,比如count.zz,它计算(ii,tt)(jj,tt)具有共同zz的实例数。 我是这样做的:

setkey(dt1,ii,jj,tt)
setkey(dt2,ii,tt)
dt1[,count.zz:= as.integer(0)]
count.zz.fun = function(z.ii,z.jj,z.tt){
return(length(intersect(dt2[.(z.ii,z.tt),zz],dt2[.(z.jj,z.tt),zz])))
}
dt1[,count.zz := count.zz.fun(ii,jj,tt), by = c("ii","jj","tt")]

在示例中,我们count.zz=2ii=1,jj=2,tt=2010因为(ii,tt)(jj,tt)都有共同zz=1zz=2count.zz=0对于ii=1,jj=3,tt=2010,因为zz=1zz=2对于不相交(jj,tt)zz集合的(ii,tt),即zz=3

我想知道是否有更快的方法来做到这一点。dt12.3百万行,zz1100,上述操作大约需要2-3 hours才能在标准台式PC上运行。

我已经标记了igraph,因为上面的结构是一个网络,并且可能有一种更快的方法来使用我不知道的igraph来做到这一点。

@Ryan建议使用sum(a %in% b)而不是length(intersect(a,b))。 以下是两个函数的比较:

library(tictoc)
N = 1000000
R = 1000
a = seq(from=1,to=N, by = 2)
b = seq(from=1,to=N, by = 3)
t = tic() 
for (rr in 1:R){
sum(a %in% b)
}
t_sum = toc(t)
t = tic() 
for (rr in 1:R){
length(intersect(a,b))
}
t_intersect = toc(t)

结果:

> t_sum = toc(t)
26.94 sec elapsed
> t_intersect = toc(t)
30.87 sec elapsed

@Ryan的建议将速度提高了~13-14%。

根据dt2的维度,你可能希望在dt2上执行自连接,以生成 tt 和 zz 组合的所有 ii 和 jj 对。然后执行连接并使用by=.EACHI计算长度

#find all pairs of ii and jj for combis of tt and zz
reldt <- dt2[dt2, .(ii=x.ii, jj=i.ii, tt, zz), on=.(tt,zz)]
#join and find the number of occurrence
reldt[dt1, on=.(ii,jj,tt), .N, by=.EACHI]

输出:

ii jj   tt N
1:  2  1 2010 2
2:  3  1 2010 0
3:  1  2 2010 2
4:  3  2 2010 0
5:  1  3 2010 0
6:  2  3 2010 0
7:  2  1 2011 2
8:  3  1 2011 1
9:  1  2 2011 2
10:  3  2 2011 0
11:  1  3 2011 1
12:  2  3 2011 0

最新更新