如何提取每个组的前n行并使用该子集计算函数?

roa*_*dom 2 r data.table

我的问题与这个问题非常相似: 如何提取每个组的前n行?

dt
         date age     name       val
1: 2000-01-01   3   Andrew  93.73546
2: 2000-01-01   4      Ben 101.83643
3: 2000-01-01   5  Charlie  91.64371
4: 2000-01-02   6     Adam 115.95281
5: 2000-01-02   7      Bob 103.29508
6: 2000-01-02   8 Campbell  91.79532
Run Code Online (Sandbox Code Playgroud)

我们有一个dt,我添加了一个名为的额外列val。首先,我们要提取每个组中的前n行。提供的链接中的解决方案是:

dt[, .SD[1:2], by=date] # where 1:2 is the index needed
dt[dt[, .I[1:2], by = date]$V1] # for speed
Run Code Online (Sandbox Code Playgroud)

我的问题是,如果该函数取决于子集信息,那么该如何将函数应用于每个组的前n行。我正在尝试应用这样的事情:

  # uses other columns for results/ is dependent on subsetted rows
  # but keep it simple for replication
do_something <- function(dt){
  res <- ifelse(cumsum(dt$val) > 200, 1, 0)  
  return(res)
}
# first 2 rows of dt by group=date
x <- dt[, .SD[1:2], by=date]
# apply do_something to first 2 rows of dt by group=date
x[, list('age'=age,'name'=name,'val'=val, 'funcVal'= do_something(.SD[1:2])),by=date]

          date age   name       val funcVal
1: 2000-01-01   3 Andrew  93.73546       0
2: 2000-01-01   4    Ben 101.83643       1
3: 2000-01-02   6   Adam 115.95281       0
4: 2000-01-02   7    Bob 103.29508       1
Run Code Online (Sandbox Code Playgroud)

我要解决这个错误吗?有没有更有效的方法可以做到这一点?我似乎无法弄清楚如何为此应用“速度”解决方案。有没有一种方法,而不必先保存子集结果并立即按日期将函数应用于前两行?

感谢您的任何帮助,下面是产生上面数据的代码:

date <- c("2000-01-01","2000-01-01","2000-01-01",
          "2000-01-02","2000-01-02","2000-01-02")
age <- c(3,4,5,6,7,8)
name <- c("Andrew","Ben","Charlie","Adam","Bob","Campbell")
val <- val <- rnorm(6,100,10)
dt <- data.table(date, age, name,val)
Run Code Online (Sandbox Code Playgroud)

Fra*_*ank 5

如果分组列不止一个,则将其折叠为一个可能更有效:

m = dt[, .(g = .GRP, r = .I[1:2]), by = date]
dt[m$r, v := ff(.SD), by=m$g, .SDcols="val"]
Run Code Online (Sandbox Code Playgroud)

这只是@eddi方法(保持行号.I,在@akrun的答案中可见)的扩展,它也保持组计数器.GRP


Re OP的评论是,他们更关注功能,好吧,从@akrun借用,有...

ff = function(x) as.integer(cumsum(x[[1]]) > 200)
Run Code Online (Sandbox Code Playgroud)

假设所有值均为非负数,则可以在C语言中更有效地进行处理,因为一旦达到阈值,累积和就可以停止。不过,对于两行的特殊情况,这无关紧要。

我的印象是,这是一个伪函数,因此毫无意义。我通常想到的许多效率改进取决于功能和数据。