4

我正在处理财务数据集的一些摘要,我想根据某个标准对摘要进行排序,但不会连续丢失剩余的摘要值。这是一个简单的例子:

set.seed(1)
tseq <- seq(Sys.time(), length.out = 36, by = "mins")
dt <- data.table(TM_STMP = tseq, COMP = rep(c(rep("A", 4), rep("B", 4), rep("C", 4)), 3), SEC = rep(letters[1:12],3), VOL = rpois(36, 3e+6))
dt2 <- dt[, list(SUM = sum(VOL), MEAN = mean(VOL)), by = list(COMP, SEC)]
dt2
   COMP SEC     SUM    MEAN
1:    A   a 9000329 3000110
2:    A   b 9001274 3000425
3:    A   c 9003505 3001168
4:    A   d 9002138 3000713

现在我想获得最高 VOL 的每个 COMP 的 SEC:

dt3 <- dt2[, list(SUM = max(SUM)), by = list(COMP)]
dt3
   COMP     SUM
1:    A 9003505
2:    B 9002888
3:    C 9005042

这给了我想要的东西,但我想将其他值保留在特定行(SEC 和 MEAN)中,使其看起来像这样(手工制作):

   COMP     SUM SEC    MEAN
1:    A 9003505   c 3001168
2:    B 9002888   f 3000963  
3:    C 9005042   k 3001681

我怎样才能做到这一点?

4

5 回答 5

3

如果您正在寻找与 SUM 的最大值对应的 SEC 和 MEAN:

 dt3 <- dt2[, list(SUM = max(SUM),SEC=SEC[which.max(SUM)],MEAN=MEAN[which.max(SUM)]), by = list(COMP)]
> dt3
   COMP     SUM SEC    MEAN
1:    A 9003110   a 3001037
2:    B 9000814   e 2999612
3:    C 9002707   i 2999741

编辑:这会更快:

dt2[dt2[, .I[which.max(SUM)], by = list(COMP)]$V1]
于 2013-10-22T19:03:40.397 回答
3

执行此操作的另一种方法是将setkeydata.table 的 to: COMP, SUM,然后mult="last"按如下方式使用:

setkey(dt2, COMP, SUM)
dt2[J(unique(COMP)), mult="last"]
#    COMP SEC     SUM    MEAN
# 1:    A   c 9002500 3000833
# 2:    B   g 9003312 3001104
# 3:    C   i 9000058 3000019

编辑:回答西蒙关于这和@metrics'之间速度差异的基准测试:

set.seed(45)
N <- 1e6
tseq <- seq(Sys.time(), length.out = N, by = "mins")

ff <- function(x) paste(sample(letters, x, TRUE), collapse="")
val1 <- unique(unlist(replicate(1e5, ff(8), simplify=FALSE)))
val2 <- unique(unlist(replicate(1e5, ff(12), simplify=FALSE)))

dt <- data.table(TM_STMP = tseq, COMP = rep(val1, each=100), SEC = rep(val2, each=100), VOL = rpois(1e6, 3e+6))
dt2 <- dt[, list(SUM = sum(VOL), MEAN = mean(VOL)), by = list(COMP, SEC)]

require(microbenchmark)

metrics <- function(x=copy(dt2)) {
    x[, list(SUM = max(SUM),SEC=SEC[which.max(SUM)],MEAN=MEAN[which.max(SUM)]), by = list(COMP)]
}

arun <- function(x=copy(dt2)) {
    setkey(x, COMP, SUM)
    x[J(unique(COMP)), mult="last"]
}

microbenchmark(ans1 <- metrics(dt2), ans2 <- arun(dt2), times=20)
# Unit: milliseconds
#                  expr      min       lq   median       uq       max neval
#  ans1 <- metrics(dt2) 749.0001 804.0651 838.0750 882.3869 1053.3389    20
#     ans2 <- arun(dt2) 301.7696 321.6619 342.4779 359.9343  392.5902    20

setkey(ans1, COMP, SEC)
setkey(ans2, COMP, SEC)
setcolorder(ans1, names(ans2))

identical(ans1, ans2) # [1] TRUE
于 2013-10-22T19:40:31.463 回答
2

从您的示例输出中,尚不清楚您要保留/删除什么,但您可以简单地在j参数中列出您的其他列DT[i, j, ]

> dt2[, list(SUM = max(SUM), SEC, MEAN), by = list(COMP)]
    COMP     SUM SEC    MEAN
 1:    A 9007273   a 3000131
 2:    A 9007273   b 3000938
 3:    A 9007273   c 2999502
 4:    A 9007273   d 3002424
 5:    B 9004829   e 3001610
 6:    B 9004829   f 2999991
 7:    B 9004829   g 2998471
 8:    B 9004829   h 2999571
 9:    C 9002479   i 3000826
10:    C 9002479   j 2999826
11:    C 9002479   k 3000728
12:    C 9002479   l 2999634
于 2013-10-22T18:58:17.787 回答
1

which.func我对@Metrics(我在下面表示为)和@Arun(我表示为)的两种不同方法的性能非常感兴趣innate.func。所以,我用上面问题中给出的例子做了一些基准测试。结果如下:

which.func <- function() {dt3 <- dt2[, list(SUM = max(SUM), SEC=SEC[which.max(SUM)], MENA=MEAN[which.max(SUM)]), by = list(COMP)]}
innate.func <- function() {dt3 <- dt2[J(unique(COMP)), mult = "last"]}
library(rbenchmark)
benchmark(which.func, innate.func, replications = 10e+6)
        test replications elapsed relative user.self sys.self
2     innate     10000000  24.689    1.000    24.259    0.425
1 which.func     10000000  32.664    1.323    32.216    0.446

当然,这可能对 which.func 有点不公平,因为它innate.func涉及对 的调用setkey,尤其是对于大样本的时间消费者而言。如果我将setkey调用包含在函数中,我会得到以下信息:

innate.func <- function() {setkey(dt2, COMP, SUM); dt3 <- dt2[J(unique(COMP)), mult = "last"]; setkey(dt2, NULL)}
         test replications elapsed relative user.self sys.self 
2 innate.func     10000000  25.271    1.000    24.834    0.430 
1  which.func     10000000  26.476    1.048    26.062    0.397 

看来,这两种方法具有非常相似的性能。@Arun 的方法在 data.table 方面可能具有更优雅的风格,并且需要更少的代码。它的缺点可能来自与maxor不同的聚合函数min,其中 @Metrics 的方法发挥了其能够应用于更一般设置的特性。

我从这两种方法中学习,并将它们放入我的工具箱中。

于 2013-10-23T08:25:24.173 回答
0

在我进一步使用此处给出的解决方案时,我遇到了另一个问题,上面显示的摘要在我的问题中,我找到了一个解决方案,我想分享。

如果我想为用户提供选择

  1. 一个聚合函数,用aggregateand表示
  2. aggregate方法应应用于的标准(摘要的变量) ,用 表示crit

然后我遇到了问题,我必须检查哪些列是剩余的(例如,参见使用 which 的@Metrics 答案)。一个简单的例子:

dt2我们从我上面的问题中获取 data.table 。现在有一个用户,想要将该aggregate = "max"方法应用于crit = "SUM"data.table 的摘要中的变量dt2。这是我发现可以正常工作的解决方案(当然欢迎任何讨论):

aggregate = "max"
crit = "SUM"
user call <- expression(do.call(aggregate, list(get(crit))))
dt2[, .SD[which(get(crit) == eval(mycall))], by = COMP]
dt2
   COMP SEC     SUM    MEAN
1:    A   c 9002500 3000833
2:    B   g 9003312 3001104
3:    C   i 9000058 3000019
于 2013-10-23T13:44:39.683 回答