【问题标题】:data.tables and sweep functiondata.tables 和扫描功能
【发布时间】:2012-04-11 17:18:53
【问题描述】:

使用 data.table,这将是“扫除”所选列中的统计信息的最快方式?

从(相当大的)DT 开始

p <- 3
DT <- data.table(id=c("A","B","C"),x1=c(10,20,30),x2=c(20,30,10))
DT.totals <- DT[, list(id,total = x1+x2) ]

我想通过索引目标列 (2:p) 来获得以下 data.table 结果以跳过键:

    id  x1  x2
[1,]    A   0.33    0.67
[2,]    B   0.40    0.60
[3,]    C   0.75    0.25

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    我相信接近以下内容(使用相对较新的set() 函数)将是最快的:

    DT <- data.table(id = c("A","B","C"), x1 = c(10,20,30), x2 = c(20,30,10))
    total <- DT[ , x1 + x2]
    
    rr <- seq_len(nrow(DT))
    for(j in 2:3) set(DT, rr, j, DT[[j]]/total) 
    DT
    #      id        x1        x2
    # [1,]  A 0.3333333 0.6666667
    # [2,]  B 0.4000000 0.6000000
    # [3,]  C 0.7500000 0.2500000
    

    FWIW,对set() 的调用采用以下形式:

    # set(x, i, j, value), where: 
    #     x is a data.table 
    #     i contains row indices
    #     j contains column indices 
    #     value is the value to be assigned into the specified cells
    

    与其他解决方案相比,我对此相对速度的怀疑是基于data.table's NEWS file 的这段话,在版本 1.8.0 的更改部分:

    o   New function set(DT,i,j,value) allows fast assignment to elements
        of DT. Similar to := but avoids the overhead of [.data.table, so is
        much faster inside a loop. Less flexible than :=, but as flexible
        as matrix subassignment. Similar in spirit to setnames(), setcolorder(),
        setkey() and setattr(); i.e., assigns by reference with no copy at all.
    
            M = matrix(1,nrow=100000,ncol=100)
            DF = as.data.frame(M)
            DT = as.data.table(M)
            system.time(for (i in 1:1000) DF[i,1L] <- i)   # 591.000s
            system.time(for (i in 1:1000) DT[i,V1:=i])     #   1.158s
            system.time(for (i in 1:1000) M[i,1L] <- i)    #   0.016s
            system.time(for (i in 1:1000) set(DT,i,1L,i))  #   0.027s
    

    【讨论】:

    • 感谢您的回答。我已经升级到data.table 1.8.0,并成功运行了上面的测试代码。当分子和分母都是 data.tables 中的整数列时,我确实收到了关于强制加倍的详细警告(不适合此处)。我会编辑这个问题。
    • 我今天在编辑方面遇到了困难:没有换行。无论如何,这是代码: for(j in 2:p){ set( dt , allrows , j , dt[[j]] / denom[[2]] ) } 对于 dt 和 denom,第 2 到 p 列是整数。我得到的警告是
    • "警告信息:在 set(dt, allrows, j, dt[[j]]/denom[[2]]) 中:强制 'double' RHS 为 'integer' 以匹配列的类型; 可能有截断精度。要么首先将目标列更改为 'double'(通过创建一个新的 'double' 向量长度 16863(整个表的 nrows)并分配它;即 'replace' 列),或者将 RHS 强制为 'integer '(例如 1L、NA_[real|integer]_、as.* 等)以使您的意图清晰并加快速度。或者,请在创建表格时预先正确设置列类型并坚持下去。”
    • 您应该密切注意这些警告。试试下面看看为什么。 D1 &lt;- data.table(1:5); class(D1[[1]]); set(D1, 1:5, 1L, 0.33); D1。将其与您可能想看到的内容进行比较:D2 &lt;- data.table(as.numeric(1:5)); class(D2[[1]]); set(D2, 1:5, 1L, 0.33); D2。然后将要扫描的列的类转换为numeric 而不是integer(在它们的初始构造中,或者在事后通过D1[[1]] &lt;- as.numeric(D1[[1]]) 之类的东西)。 (可能有更有效的方法来完成最后的操作。)
    • @Josh 当将新列插入列槽(而不是将1:nrow 传递为i)时(使用set():=),强制警告消失(只有在更新列的子集时才需要强制)。
    猜你喜欢
    • 1970-01-01
    • 2015-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 2022-07-22
    相关资源
    最近更新 更多