例如,
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)]
答案 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
,然后使用与第一个解决方案非常相似的代码。