【问题标题】:Calculations based on a dynamic subgroup of a data.table基于 data.table 的动态子组的计算
【发布时间】:2018-12-08 20:27:49
【问题描述】:

我的问题与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 的数据的第三行,我希望在 x > 3 的行中min(y)(这将是值 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 作为结果

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    方法一:

    既然您说我们可以假设数据按x 排序,您可以使用从y 末尾开始的累积最小值。我们删除了第一个观察结果,以便进行&gt; 搜索而不是&gt;=

    tmp$min_y <- c(rev(cummin(rev(tmp$y[-1]))), NA)
    

    更新:旧方法有效地进行了 &gt;= 搜索,而不是 &gt;。更新为&gt;


    方法二:Data.table

    如果您想使用data.table,您可以尝试按每一行分组,然后在J 中设置子集。 ifelse 是必需的,这样当我们在最后一行时,我们不会取任何值的最小值:

    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
    

    因为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
    

    【讨论】:

      【解决方案2】:

      一种选择是自非平等加入

      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
      

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

          【解决方案4】:

          这里有一些解决方案:

          1) rollapply 假设tmp 已排序(如果没有排序),我们可以使用rollapply 来获得这样的紧凑解决方案。请注意,当rollapplywidth 参数是一个列表时,其元素被视为应用min 的偏移向量。

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

          给予:

               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
          

          2) sqldf 使用 SQL 将 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")
          

          给予:

              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
          

          【讨论】:

            猜你喜欢
            • 2018-01-22
            • 1970-01-01
            • 2020-04-16
            • 1970-01-01
            • 1970-01-01
            • 2018-08-28
            • 1970-01-01
            • 2015-12-22
            • 2014-01-04
            相关资源
            最近更新 更多