如何在按列(x,y)分组时有效地计算列z的多个分位数

时间:2017-12-07 19:01:35

标签: r data.table

例如,

set.seed(2017)
dt <- data.table(
  x = sample(LETTERS, size = 10^7, replace = T),
  y = sample(LETTERS, size = 10^7, replace = T),
  z = sample(10^7, size = 10^7, replace = T)
)

          x y       z
       1: Y U 6830565
       2: N V 5063188
       3: M L 7551719
      ---            
 9999998: C J 8951173
 9999999: C T 2265750
10000000: L B 1303897

我想按(x,y)分组并计算关于z的多个事项。这有效,

system.time(
  result1 <- dt[, list(
    firstval = first(z), 
    q1 = quantile(z, 0.5), 
    q2 = quantile(z, 0.75),
    q3 = quantile(z, 0.9)
    ), keyby=list(x, y)]
)

     x y firstval      q1      q2      q3
  1: A A  4600349 4982000 7469398 8981072
  2: A B  9731616 4984859 7493566 9028473
  3: A C  3672771 5071190 7496436 8972589
 ---                                     
674: Z X  1908196 5048164 7521350 9014482
675: Z Y  2933076 4985024 7500346 8977680
676: Z Z  6215175 5018085 7524220 9031993

但是不必要地慢,因为每次调用分位数都可能会重新排序相同的数据。我可以按照以下方式对其进行矢量化

system.time(
  result2 <- dt[, list(
    firstval = first(z), 
    quant = c(0.5, 0.75, 0.9), 
    val = quantile(z, c(0.5, 0.75, 0.9))
  ), keyby=list(x, y)]
)

      x y firstval quant     val
   1: A A  4600349  0.50 4982000
   2: A A  4600349  0.75 7469398
   3: A A  4600349  0.90 8981072
  ---                           
2026: Z Z  6215175  0.50 5018085
2027: Z Z  6215175  0.75 7524220
2028: Z Z  6215175  0.90 9031993

^^这个更快但现在我的数据形状错误(并且可能显着,大小不必要地更大)。我可以dcast得到我想要的结果,但这仍然是内存效率低下的。

如何在不改变数据形状的情况下有效地计算分位数?理想情况下,我正在寻找像

这样的东西
result3 <- dt[, c(
  list(firstval = first(z)), 
  c("q1", "q2", "q3") = t(quantile(z, c(0.5, 0.75, 0.9)))
), keyby=list(x, y)]

2 个答案:

答案 0 :(得分:6)

我们可以使用as.list代替多次调用quantile

system.time(
 result2 <- dt[, c(list(
  firstval = first(z)), as.list( 
  quantile(z, c(0.5, 0.75, 0.9)))
 ), keyby=list(x, y)]
)

答案 1 :(得分:5)

@akrun已经有了一个很好的解决方案,但您也可以在data.table调用中使用代码块:

system.time(
  result2b <- dt[, {
      the_quantiles = quantile(z, c(0.5, 0.75, 0.9))
      list(
        firstval = first(z), 
        q1 = the_quantiles[1], 
        q2 = the_quantiles[2],
        q3 = the_quantiles[3]
      )
    }, keyby=list(x, y)]
)

注意如何在一次调用中首先计算the_quantiles,然后使用与第一个解决方案非常相似的代码。