【问题标题】:data.table - apply vector of valuesdata.table - 应用值向量
【发布时间】:2018-07-26 23:35:43
【问题描述】:

我有点被这个问题所困扰。 我有一个 beta 分布参数的数据表,数据表中的每一行对应于该分布的相对概率,以代表实际结果。

我想计算一些样本值的累积分布函数。使用 sapply,代码如下所示:

beta_dists <- data.table(data.frame(probs = c(0.4,0.3,0.3), a = c(0.0011952,0.001,0.00809), b = c(837,220,624), scale = c(1.5e9,115e6,1.5e6)))
xx <- seq(0,1.5e9,length = 2^12)

system.time(FX <- sapply(xx, function(x) (beta_dists[x < scale,.(FX = sum(probs * (1 - pbeta(x / scale, a, b))))])$FX))

但是,这很慢,而且看起来不是很优雅......关于如何让它变得更好的任何想法?

【问题讨论】:

    标签: r data.table sapply


    【解决方案1】:

    这里建议通过将您的 xx 转换为要在 i 中使用的 data.table 来使用非 equi 连接:

    ans <- beta_dists[dtx, on=.(scale > x), allow.cartesian=TRUE,
        sum(probs * (1 - pbeta(x / x.scale, a, b))), by=.EACHI]$V1
    

    检查:

    #last element is NA in ans whereas its NULL in FX
    identical(unlist(FX), head(ans$V1, -1))
    #[1] TRUE
    

    计时码:

    opmtd <- function() {
        sapply(xx, function(x) (beta_dists[x < scale,.(FX = sum(probs * (1 - pbeta(x / scale, a, b))))])$FX)
    }
    
    nonequiMtd <- function() {
        beta_dists[dtx, on=.(scale > x), allow.cartesian=TRUE, sum(probs * (1 - pbeta(x / x.scale, a, b))), by=.EACHI]   
    }
    
    vapplyMtd <- function() {
        dt[, res := vapply(x, f, 0)]
    }
    
    library(microbenchmark)
    microbenchmark(opmtd(), nonequiMtd(), vapplyMtd(), times=3L)
    

    时间安排:

    Unit: milliseconds
             expr        min         lq       mean     median         uq        max neval
          opmtd() 2589.67889 2606.77795 2643.77975 2623.87700 2670.83018 2717.78336     3
     nonequiMtd()   19.59376   21.12739   22.28428   22.66102   23.62954   24.59805     3
      vapplyMtd() 1928.25841 1939.91866 1960.31181 1951.57891 1976.33852 2001.09812     3
    

    数据:

    library(data.table)
    beta_dists <- data.table(probs = c(0.4,0.3,0.3), a = c(0.0011952,0.001,0.00809), b = c(837,220,624), scale = c(1.5e9,115e6,1.5e6))
    xx <- seq(0, 1.5e9, length = 2^12)
    dtx <- data.table(x=xx)
    

    【讨论】:

    • 我真的很喜欢非等连接解决方​​案,虽然我应该更好地理解笛卡尔连接,但结果不一样? beta_dists x), allow.cartesian=TRUE, sum(probs * (1 - pbeta(x / scale, a, b))), by=.EACHI]
    • 应该是pbeta(x / x.scale, a, b) 而不是pbeta(x / scale, a, b)。注意x.x.x[i, on=...] 连接中引用 x 中的列。
    • 道歉 - 我有一个过时的 data.table 版本,这就是我遇到错误的原因。这很棒!谢谢
    【解决方案2】:

    我唯一的想法是另一种方式,即通过包含您的样本值的数据表进行压缩:

    dt <- data.table(x = xx, res = 0)
    f <- function(x) {
      beta_dists[x < scale, sum(probs * (1 - pbeta(x / scale, a, b)))]
    }
    system.time(dt[, res := vapply(x, f, 0)])
    

    似乎要快一些。例如,当我将您的样本大小增加到 2^14 时,您的原始代码在我的机器上运行了 7 秒,但我提出的代码在 5 秒内完成了。

    我认为最慢的部分是 pbeta() 函数,但我可能错了。

    【讨论】:

    • 非常感谢,它确实看起来确实更快,并且产生了正确的结果。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-04
    相关资源
    最近更新 更多