连接各个时段以获取时间序列,同时针对不同的起点

时间:2019-02-17 09:32:59

标签: r data.table sequence purrr

我有以下示例数据:

library(data.table)
set.seed(42)
t <- data.table(time=1:1000, period=round(runif(100,1,5)))
p <- data.table(id=1:10, cut=sample(1:100,5))


> t[62:71]
    time period
 1:   62      5
 2:   63      4
 3:   64      3
 4:   65      4
 5:   66      2
 6:   67      2
 7:   68      4
 8:   69      4
 9:   70      2
10:   71      1

> head(p)
   id cut
1:  1  63
2:  2  22
3:  3  99
4:  4  38
5:  5  91
6:  6  63

其中t给出了与时间点相关的periods的矢量,而p为每个人提供了time的分界点。

对于p中的每个人,我想从该人的临界值开始,并通过串联periods来创建4个时间点的序列。例如,对于人1,从时间63开始,序列将为6363+4=6767+2=6969+4=73

理想情况下,输出为:

> head(res)
   id  t1   t2   t3   t4
    1  63   67   69   73
    2  22   24   29   32
    3  99  103  105  109
    4  38   40   43   44
    5  91   95  100  103
    6  63   67   69   73

我之前学习了如何使用accumulate::purrriterative cumsum where sum determines the next position to be added)创建序列。但是,我想知道是否可以使用data.table或其他软件包针对不同的人同时执行这样的操作,但是由于数据集很大,因此避免了for循环。


编辑:时间值与行索引不一致的版本

library(data.table)
set.seed(42)
t <- data.table(time=1001:2000, period=round(runif(100,1,5)))
p <- data.table(id=1:10, cut=sample(1:100,5))

与上面类似,除了

> t[62:71]
    time period
 1: 1062      5
 2: 1063      4
 3: 1064      3
 4: 1065      4
 5: 1066      2
 6: 1067      2
 7: 1068      4
 8: 1069      4
 9: 1070      2
10: 1071      1

其中t$time[i]不等于i,这禁止了Jaap的第一个解决方案。

2 个答案:

答案 0 :(得分:3)

For循环不一定很糟糕或效率很低。如果使用得当,它们可以有效解决您的问题。

对于您当前的问题,我将在软件包中使用for循环,因为data.table是通过引用进行更新的,因此非常有效:

res <- p[, .(id, t1 = cut)]

for(i in 2:4) {
  res[, paste0("t",i) := t[res[[i]], time + period] ]
}

给出:

> res
    id t1  t2  t3  t4
 1:  1 63  67  69  73
 2:  2 22  24  29  32
 3:  3 99 103 105 109
 4:  4 38  40  43  44
 5:  5 91  95 100 103
 6:  6 63  67  69  73
 7:  7 22  24  29  32
 8:  8 99 103 105 109
 9:  9 38  40  43  44
10: 10 91  95 100 103

或者,您可以选择更新p,如下所示:

for(i in 2:4) {
  p[, paste0("t",i) := t[p[[i]], time + period]]
}
setnames(p, "cut", "t1")

给出相同的结果。


对于更新后的示例数据,您应将上述方法更改为:

for(i in 2:4) {
  p[, paste0("t",i) := t[match(p[[i]], t$time), time + period]]
}
setnames(p, "cut", "t1")

答案 1 :(得分:0)

我将使用while()循环。

while (ncol(p) - 1 < 4) {
  p <- cbind(p, p[[ncol(p)]] + t$period[p[[ncol(p)]]])
} 

> head(p)
   id cut  V2  V2  V2
1:  1  63  67  69  73
2:  2  22  24  29  32
3:  3  99 103 105 109
4:  4  38  40  43  44
5:  5  91  95 100 103
6:  6  63  67  69  73