基于数据表的动态子组的计算

时间:2018-12-06 19:18:12

标签: r data.table

我的问题与Subset by group with data.table有关,但有所不同。

想象一个这样的数据集:

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

对于数据的每一行,我想计算一个新值z,对于所有具有较大x值的行,它都是min(y)。例如,对于x为3的数据的第三行,我希望min(y)在x> 3(即值为5)的行中。出于我们的目的和目的,您可以假定数据已经按x排序。

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

min.y <- function(val, dt) {
  dt[x > val, min(y)]
}

但是致电tmp[, z:= fun(x, tmp)]会导致警告消息:

In min(y) : no non-missing arguments to min; returning Inf

执行此操作的正确方法是什么?

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

4 个答案:

答案 0 :(得分:5)

方法1:

由于您说过我们可以假设数据按y排序,因此可以使用从>末尾开始的累计最小值。我们切出第一个观察值,以便我们进行>=而不是tmp$min_y <- c(rev(cummin(rev(tmp$y[-1]))), NA) 的搜索:

>=

更新:旧方法有效地进行了>搜索,而不是>。更新为执行data.table


方法2:Data.table

如果您想使用J,则可以尝试按每行分组,然后在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 中进行分组。需要ifelse,以便当我们在最后一行时,不要取无值的最小值:

5

由于5是最小值,最终所有值都是tmp <- data.table(x = 1:10, y = c(27, 70, 54, 18, 50, 44, 22, 73, 47, 58)) 。让我们做些更有趣的事情:

#     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

我们的结果将是:

while

答案 1 :(得分:3)

一种选择是自我非股权联接

tmp[, min_y := .SD[.SD, min(y, na.rm = TRUE), on = .(x > x),
         by = .EACHI]$V1][is.infinite(min_y), min_y := NA_real_][]
#      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

答案 2 :(得分:2)

对于它的价值,还有另一种可能的方法(不确定它是否比其他方法更好或更坏):

tmp[, z := min(tmp$y[(.I+1):NROW(tmp)]), by = 1:NROW(tmp)]

答案 3 :(得分:2)

以下是一些解决方案:

1)滚动应用假设tmp已排序(如果未排序,则排序),我们可以使用rollapply来获得一个紧凑的解决方案。请注意,当width的{​​{1}}自变量是一个列表时,其元素被视为偏移量向量,将在其上应用rollapply

min

给予:

library(data.table)
library(zoo)

tmp[, min := rollapply(y, lapply(pmax(.N:1-1, 1), seq), min, fill = NA)]

2)sqldf 使用SQL按照指示的条件将 x y min 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 与其自身连接,并像这样对组进行最小化。 tmp不需要排序。

tmp

给予:

library(data.table)
library(sqldf)

sqldf("select a.*, min(b.y) min 
       from tmp a left join tmp b on b.x > a.x group by a.rowid")