【问题标题】:aggregate per variable over which sums are calculated in R data.table在 R data.table 中计算总和的每个变量的聚合
【发布时间】:2020-03-26 10:29:30
【问题描述】:

我有一些时间数据

library(data.table); library(lubridate); set.seed(42)
dat <- rbind(data.table(time=as.POSIXct("2019-01-01 08:00:00") + round(runif(10,60,1e4)), val=runif(10),group=1)[order(time), id:=seq_len(.N)],
             data.table(time=as.POSIXct("2019-02-01 18:00:00") + round(runif(10,60,1e4)), val=runif(10),group=2)[order(time), id:=seq_len(.N)])
> dat[order(group,id)]
                   time         val group id
 1: 2019-01-01 08:23:19 0.117487362     1  1
 2: 2019-01-01 08:48:24 0.934672247     1  2
 3: 2019-01-01 09:27:00 0.940014523     1  3
 4: 2019-01-01 09:47:19 0.462292823     1  4
 5: 2019-01-01 09:49:51 0.474997082     1  5
 6: 2019-01-01 09:57:48 0.560332746     1  6
 7: 2019-01-01 10:03:02 0.978226428     1  7
 8: 2019-01-01 10:18:35 0.255428824     1  8
 9: 2019-01-01 10:32:33 0.457741776     1  9
10: 2019-01-01 10:36:15 0.719112252     1 10
11: 2019-02-01 18:14:39 0.003948339     2  1
12: 2019-02-01 18:23:59 0.811055141     2  2
13: 2019-02-01 19:05:39 0.007334147     2  3
14: 2019-02-01 19:15:03 0.906601408     2  4
15: 2019-02-01 19:26:11 0.832916080     2  5
16: 2019-02-01 20:19:30 0.611778643     2  6
17: 2019-02-01 20:30:46 0.737595618     2  7
18: 2019-02-01 20:31:03 0.207658973     2  8
19: 2019-02-01 20:37:50 0.685169729     2  9
20: 2019-02-01 20:44:50 0.388108283     2 10

我想在接下来的一小时内为每个time 的值计算val 的总和。例如,对于 ID 1,这将是 ID 1 和 2 的 val 之和(因为 ID 3 的时间比 ID 1 晚一个多小时),对于 ID 2,这将是 ID 2 的 val 之和到 4,以此类推。这会产生所需的输出(仅适用于第 1 组)

> res
                   time       val id     new1     new2
 1: 2019-01-01 08:23:19 0.1174874  1 1.052160 1.052160
 2: 2019-01-01 08:48:24 0.9346722  2 2.336979 2.336979
 3: 2019-01-01 09:27:00 0.9400145  3 3.671292 3.671292
 4: 2019-01-01 09:47:19 0.4622928  4 3.908132 3.908132
 5: 2019-01-01 09:49:51 0.4749971  5 3.445839       NA
 6: 2019-01-01 09:57:48 0.5603327  6 2.970842       NA
 7: 2019-01-01 10:03:02 0.9782264  7 2.410509       NA
 8: 2019-01-01 10:18:35 0.2554288  8 1.432283       NA
 9: 2019-01-01 10:32:33 0.4577418  9 1.176854       NA
10: 2019-01-01 10:36:15 0.7191123 10 0.719112       NA

最后可能有两种行为:

  1. 序列按原样处理的地方;
  2. 只有在至少一小时后没有 ID 为 time 的 ID 才计算总和,并且所有其他 ID 都设置为 NA(首选)。

我怀疑解决这个问题需要我在j 中进行子集化,但这是我经常遇到但无法解决的问题。我还没有理解这个的一般方法。

【问题讨论】:

  • 虽然不清楚。如果您正在对“08”小时求和,为什么使用第 6 次观察 09
  • 因为它不是时钟时间而是time 加上一小时。因此,所有ids 都包含在其中time &lt; time[i] + 3600
  • 之前发布的数据与种子不一致。对此表示歉意。现在应该是正确的。
  • 我明白了,太好了!如果您有快速到达sum2 的方法,我们将不胜感激,也可以让帖子完整,以防以后对其他人有用。
  • 是的,如果所有后续时间都在当前时间之后不到一小时,这将是NA,因为当前时间之后没有整小时。

标签: r data.table aggregate


【解决方案1】:

这可能是一个带有连接的循环

dat1 <- dat[order(id)]
out <- rbindlist(lapply(dat1$id, function(i) {
      d1 <- dat1[seq_len(.N) >= match(i, id)]
      d1[d1[, .(time = time %m+% hours(1))], .(time1 = time, val, new1 = sum(val)),
         on = .(time <= time), by = .EACHI][1]
      }))[, time := NULL][]
setnames(out, 1, "time")
out[time < time[2]   %m+% hours(1), new2 := new1]
out
#                   time       val      new1     new2
# 1: 2019-01-01 08:23:19 0.1174874 1.0521596 1.052160
# 2: 2019-01-01 08:48:24 0.9346722 2.3369796 2.336980
# 3: 2019-01-01 09:27:00 0.9400145 3.6712924 3.671292
# 4: 2019-01-01 09:47:19 0.4622928 3.9081319 3.908132
# 5: 2019-01-01 09:49:51 0.4749971 3.4458391       NA
# 6: 2019-01-01 09:57:48 0.5603327 2.9708420       NA
# 7: 2019-01-01 10:03:02 0.9782264 2.4105093       NA
# 8: 2019-01-01 10:18:35 0.2554288 1.4322829       NA
# 9: 2019-01-01 10:32:33 0.4577418 1.1768540       NA
#10: 2019-01-01 10:36:15 0.7191123 0.7191123       NA

更新

对于新数据,我们可以split分组并应用相同的方法

f1 <- function(data) {
              lst1 <- split(data, data[["group"]])
              rbindlist(lapply(lst1, function(.dat) {
                out <- rbindlist(lapply(.dat$id, function(i) {
                      d1 <- .dat[seq_len(.N) >= match(i, id)]
                      d1[d1[, .(time = time %m+% hours(1))], .(time1 = time, val, new1 = sum(val)),
                         on = .(time <= time), by = .EACHI][1]
                      }))[, time := NULL][]
                setnames(out, 1, "time")

                out[time[.N]-time > hours(1), new2 := new1][] 
              })
              )}

 f1(dat1)
 #                  time         val      new1      new2
 #1: 2019-01-01 08:23:19 0.117487362 1.0521596 1.0521596
 #2: 2019-01-01 08:48:24 0.934672247 2.3369796 2.3369796
 #3: 2019-01-01 09:27:00 0.940014523 3.6712924 3.6712924
 #4: 2019-01-01 09:47:19 0.462292823 3.9081319 3.9081319
 #5: 2019-01-01 09:49:51 0.474997082 3.4458391        NA
 #6: 2019-01-01 09:57:48 0.560332746 2.9708420        NA
 #7: 2019-01-01 10:03:02 0.978226428 2.4105093        NA
 #8: 2019-01-01 10:18:35 0.255428824 1.4322829        NA
 #9: 2019-01-01 10:32:33 0.457741776 1.1768540        NA
#10: 2019-01-01 10:36:15 0.719112252 0.7191123        NA
#11: 2019-02-01 18:14:39 0.003948339 0.8223376 0.8223376
#12: 2019-02-01 18:23:59 0.811055141 1.7249907 1.7249907
#13: 2019-02-01 19:05:39 0.007334147 1.7468516 1.7468516
#14: 2019-02-01 19:15:03 0.906601408 1.7395175 1.7395175
#15: 2019-02-01 19:26:11 0.832916080 1.4446947        NA
#16: 2019-02-01 20:19:30 0.611778643 2.6303112        NA
#17: 2019-02-01 20:30:46 0.737595618 2.0185326        NA
#18: 2019-02-01 20:31:03 0.207658973 1.2809370        NA
#19: 2019-02-01 20:37:50 0.685169729 1.0732780        NA
#20: 2019-02-01 20:44:50 0.388108283 0.3881083        NA

【讨论】:

  • 我正在尝试了解解决方案的工作原理,看看我可以在哪里添加帖子中提到的分组变量。这可能吗?
  • @bumblebee 如果它需要一个分组列,它应该在on
  • 仅将其添加到on 会产生groupi 中找不到的错误。也许在行动中最容易看到它。我在帖子中添加了一个分组变量(保持第 1 组的数据相同有点复杂)。您能否更新解决方案以显示其工作原理?
  • 然而,我注意到new2 中有一个细微的错误:如果在随后的ids 之间有超过一小时的休息时间,它会产生NA。这不应该是这样。截止时间不应是“下一小时内没有 ID”,而是当前时间之后的“所有后续 ID 不到一小时”。
  • 不用担心。我想出了一个解决方案并将其编辑到您的答案中。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-08
  • 1970-01-01
  • 2022-07-06
  • 2019-09-03
  • 2016-06-03
  • 2014-09-14
  • 1970-01-01
相关资源
最近更新 更多