目的
我有事件ID(即oid
)和与每个事件关联的二元级观察:代理(即aid
),合作伙伴(即pid
)。事件按事件发生的时间(即o4.in
)排序。此外,我有一个变量来指示两列中的一对值是否出现在上一个事件中(即j2.consecutive
)。
我使用ddply
按组聚合虚拟变量,如以下示例中所述(例如,t2
创建aj1.consecutive
和apj1.consecutive
)。但是,对于 4m 的观察,代码花费了太多时间,并且 Rstudio 在运行代码时经常终止。
除了应用ddply
之外,是否有更快,更紧凑的方法来完成相同的任务?
数据
library(tidyverse)
library(tibble)
library(data.table)
rename <- dplyr::rename
select <- dplyr::select
set.seed(10001)
cases <- sample(1:5, 1000, replace=T)
set.seed(10002)
agent <- sample(1:20, 1000, replace=T)
set.seed(10003)
partner <- sample(1:20, 1000, replace=T)
set.seed(123)
n <- 1000 # no of random datetimes needed
minDate <- as.POSIXct("1999/01/01")
maxDate <- as.POSIXct("2000-01-01")
epoch <- "1970-01-01"
timestamps <-
as.POSIXct(pmax(runif(n, minDate, maxDate), runif(n, minDate, maxDate)), origin = epoch)
df <-
data.frame(cases, agent, partner, timestamps) %>%
rename(
aid = agent,
pid = partner,
oid = cases,
o4.in = timestamps
) %>%
filter(aid != pid) %>%
arrange(o4.in)
t <- setDT(df)[order(o4.in)]
t[, oid.lag.a := shift(oid), by = aid
][, oid.lag.p := shift(oid), by = pid]
t <-
t[, j2.consecutive := fcoalesce(+(oid.lag.a == oid.lag.p), 0L)] %>%
arrange(aid, o4.in)
当前方法
# aggregating the dummy variable by groups
t2 <-
t %>%
ungroup %>%
ddply(c('oid', 'aid'), function(i){
i %>%
mutate(aj1.consecutive = (sum(j2.consecutive) - j2.consecutive)/(n()-1))
} , .progress = 'text') %>%
arrange(oid, pid) %>%
ddply(c('oid', 'pid'), function(i){
i %>%
mutate(apj1.consecutive = (sum(j2.consecutive) - j2.consecutive)/(n()-1))
} , .progress = 'text') %>%
arrange(aid, o4.in)
更有效的data.table
选项是使用:=
和set
函数。 据?':='
set 是 := 的低开销可循环版本。它对于通过引用(使用 for 循环)重复更新某些列的行特别有用。
此外,基于?setorder
setorderv)根据提供的列(和列顺序)对data.table的行重新排序。它通过引用对表重新排序,因此非常节省内存。
下面的代码通过引用分配(:=
),按"oid","aid"或"oid","pid"分组,并按setorder
进行排序,从而使其更有效率。copy
是在原始对象上进行的,因此在执行分配时不会更改它
library(data.table)
t3 <- copy(t)
t3[, aj1.consecutive := (sum(j2.consecutive) -
j2.consecutive)/(.N-1), .(oid, aid)]
setorder(t3, oid, pid)
t3[, apj1.consecutive := (sum(j2.consecutive) -
j2.consecutive)/(.N-1), .(oid, pid)]
setorder(t3, aid, o4.in)
- 检查OP的输出
all.equal(t2, t3, check.attributes = FALSE)
[1] TRUE