concatenate periods to get time sequences, simultaneously for different starting points

帅比萌擦擦* 提交于 2019-12-24 01:09:28

问题


I have the following example data:

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

where t gives some vector of periods associated with time points, and p gives for each person a cutoff in time.

For each person in p, I would like to start at the person's cutoff and create a sequence of 4 time points by concatenating the periods. For example, for person 1, starting at time 63, the sequence would be 63, 63+4=67, 67+2=69 and 69+4=73.

Ideally, the output would then be:

> 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

I learned before how to create the sequences using accumulate::purrr (iterative cumsum where sum determines the next position to be added). However, I wonder whether something like this can be done simultaneously for different persons using data.table or other packages but avoiding for-loops as the datasets are rather large.


edit: version where time values do not coincide with row indicies

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))

is similar as above, except for

> 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

where t$time[i] does not equal i, which prohibits Jaap's first solution.


回答1:


For-loops aren't necessarily bad or inefficient. When used correctly, they can be an efficient solution for your problem.

For your current problem I would use a for-loop with the data.table-package which is efficient because the data.table is updated by reference:

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

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

which gives:

> 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

Alternatively, you can choose to update p as follows:

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

which gives the same result.


For the updated example data, you should change the above method to:

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



回答2:


I would use a while() loop.

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


来源:https://stackoverflow.com/questions/54731843/concatenate-periods-to-get-time-sequences-simultaneously-for-different-starting

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!