【问题标题】:Select last row by group for all columns data.table为所有列 data.table 按组选择最后一行
【发布时间】:2013-01-03 16:42:18
【问题描述】:

我对以下事情感到惊讶:

R) system.time(lastOrder <- order[,lapply(.SD,tail,1),by="TRADER_ID,EXEC_IDATE"]);
utilisateur     système      écoulé 
       1.45        0.00        1.53 
R) nrow(order)
[1] 75301
R) ncol(order)
[1] 23

以为很长,然后就做了

R) system.time(lastOrder <- order[,list(test=tail(EXEC_IDATE,1)),by="TRADER_ID,EXEC_IDATE"]);
utilisateur     système      écoulé 
       0.14        0.00        0.14 

据我了解,如果您知道要选择的所有行,并且大部分工作都已完成,那么我不明白为什么将其应用于所有列应该长 10 倍。我在第一段代码上做错了吗,这是我知道按组选择最后一行的唯一方法

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    按组的最后一行:

    DT[, .SD[.N], by="TRADER_ID,EXEC_IDATE"]            # (1)
    

    或者,更快(尽可能避免使用.SD,以提高速度):

    w = DT[, .I[.N], by="TRADER_ID,EXEC_IDATE"][[3]]    # (2)
    DT[w]
    

    请注意,以下功能请求将使方法 (1) 与方法 (2) 一样快:

    FR#2330 Optimize .SD[i] query to keep the elegance but make it faster unchanged.

    【讨论】:

    • 可能这样更好w = DT[, list(IDX=.I[.N]), by="TRADER_ID,EXEC_IDATE"]$IDXDT[w]
    • 看起来功能请求现在是 here 并计划用于 data.table v. 2.0
    【解决方案2】:

    这样的事情怎么样? (合成数据旨在模仿我可以从问题中推断出的关于您的信息)

    tmp <- data.table(id = sample(1:20, 1e6, replace=TRUE),
                      date = as.Date(as.integer(runif(n=1e6, min = 1e4, max = 1.1e4)),
                                     origin = as.Date("1970-01-01")),
                      data1 = rnorm(1e6),
                      data2 = rnorm(1e6),
                      data3 = rnorm(1e6))
    
    > system.time(X <- tmp[, lapply(.SD, tail, 1), by = list(id, date)])
      user  system elapsed 
      1.95    0.00    1.95
    
    > system.time(Y <- tmp[, list(tail(data1, 1)), by = list(id, date)])
      user  system elapsed 
      1.24    0.01    1.26 
    
    > system.time({
        setkey(tmp, id, date)
        Z <- tmp[unique(tmp)[, key(tmp), with=FALSE], mult="last"]
    })
      user  system elapsed 
      0.90    0.02    0.92 
    

    保证相同顺序后X和Z相同:

    > identical(setkey(X, id, date), setkey(Z, id, date))
    [1] TRUE
    

    我的lapplytail 和 1-column tail 之间的区别没有你的那么大,但是没有你的数据结构,很难说更多。

    另外,请注意,此方法中的大部分时间都是设置密钥。如果表格已经按分组列排序,它会非常快:

    > system.time(Z <- tmp[unique(tmp)[, key(tmp), with=FALSE], mult="last"])
      user  system elapsed 
      0.03    0.00    0.03 
    

    或者,您可以使用临时列将多列问题转换为 1 列问题:

    > system.time({
      tmp[, row.num := seq_len(nrow(tmp))]
      W <- tmp[tmp[, max(row.num), by = list(id, date)]$V1][, row.num := NULL]
      tmp[, row.num := NULL]
    })
    user  system elapsed 
    0.92    0.00    1.09 
    
    > identical(setkey(X, id, date), setkey(W, id, date))
    [1] TRUE
    

    【讨论】:

    • 添加到@user1935457: Z1 &lt;- tmp[, lapply(.SD, last), by = .(id, date)]) 做同样的工作并且和X &lt;- tmp[, lapply(.SD, tail, 1), by = list(id, date)] 一样快
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多