基于data.table的动态子组的计算

Mer*_*rik 3 r data.table

我的问题与groupset的子集有关,data.table但不同.

想象一下这样的数据集:

tmp <- data.table(x = 1:10, y = c(27, 70, 54, 18, 50, 44, 22, 73, 6, 5))
Run Code Online (Sandbox Code Playgroud)

对于数据的每一行,我想计算一个新值z,它是min(y)所有具有较大x值的行.例如,对于x为3的数据的第三行,我想要min(y)x> 3的行(这将是值5).出于我们的意图和目的,您可以假设数据已经按x排序.

起初我想过使用这样的函数:

min.y <- function(val, dt) {
  dt[x > val, min(y)]
}
Run Code Online (Sandbox Code Playgroud)

但是调用tmp[, z:= fun(x, tmp)]会产生一条警告信息:

In min(y) : no non-missing arguments to min; returning Inf
Run Code Online (Sandbox Code Playgroud)

这样做的正确方法是什么?

PS:显然,对于最后一行,我希望得到NA作为结果

Mik*_* H. 5

方法1:

既然你说我们可以假设数据已经排序,x你可以使用从结尾开始的累积最小值y.我们删除了第一个观察,以便我们进行>搜索而不是>=:

tmp$min_y <- c(rev(cummin(rev(tmp$y[-1]))), NA)
Run Code Online (Sandbox Code Playgroud)

更新:旧方法有效地进行了>=搜索,而不是>.更新了>.


方法2:Data.table

如果您想使用data.table,可以尝试按行分组,然后在其中进行分组J.ifelse是必需的,所以当我们在最后一行时,我们不采取没有值的min:

tmp[, "min_y" := {curr_x <- x
                  tmp_subs <- tmp[x > curr_x]
                  ifelse(nrow(tmp_subs)>0, min(tmp[x > curr_x][["y"]]), NA_real_)},
    by = 1:nrow(tmp)]

tmp
#     x  y min_y
# 1:  1 27     5
# 2:  2 70     5
# 3:  3 54     5
# 4:  4 18     5
# 5:  5 50     5
# 6:  6 44     5
# 7:  7 22     5
# 8:  8 73     5
# 9:  9  6     5
#10: 10  5     NA
Run Code Online (Sandbox Code Playgroud)

因为5最终的价值是最终的一切5.让我们更有趣一点:

tmp <- data.table(x = 1:10, y = c(27, 70, 54, 18, 50, 44, 22, 73, 47, 58))
Run Code Online (Sandbox Code Playgroud)

我们的结果将是:

#     x  y min_y
# 1:  1 27    18
# 2:  2 70    18
# 3:  3 54    18
# 4:  4 18    22
# 5:  5 50    22
# 6:  6 44    22
# 7:  7 22    47
# 8:  8 73    47
# 9:  9 47    58
#10: 10 58    NA
Run Code Online (Sandbox Code Playgroud)