代码之家  ›  专栏  ›  技术社区  ›  Tim unnamed eng

稀疏向量与R中另一向量的分量函数的分量积

r
  •  0
  • Tim unnamed eng  · 技术社区  · 14 年前

    假设我有两个向量 b a . 后者的组成部分( )几乎都是零除了少数。

    如果我想计算a的分量积和b的分量函数(如exp),我可以

    a*exp(b)
    

    然而,对于a的大多数零组分,对b的相应组分的exp的评估将是一种浪费。

    我想知道在这种情况下,是否有可能在R中更有效地编程?或者没有必要改变。谢谢!

    4 回复  |  直到 14 年前
        1
  •  2
  •   Gavin Simpson    14 年前

    要详细说明DWin的答案和您对它的评论,只需跟踪 0 再加上一些琐碎的答案:

    ## Dummy data
    set.seed(1)
    a <- sample(0:10, 100, replace = TRUE)
    b <- runif(100)
    
    ## something to hold results
    out <- numeric(length(a))
    ## the computations you *want* to do
    want <- !a==0
    ## fill in the wanted answers
    out[want] <- a[want] * exp(b[want])
    

    结果是正确的:

    > all.equal(out, a * exp(b))
    [1] TRUE
    

    如果需要,可以将其包装为一个函数:

    myFun <- function(a, b) {
        out <- numeric(length(a))
        want <- !a==0
        out[want] <- a[want] * exp(b[want])
        return(out)
    }
    

    那就用它吧

    > all.equal(out, myFun(a, b))
    [1] TRUE
    

    但是 没有比使用 a * exp(b) 直接的。两者 * exp() 是矢量化的,所以运行速度会非常快,比目前各种答案中使用的任何预订保持措施都快得多。

    你是否需要簿记解决方案将取决于你的功能有多贵( 经验() 在你的例子中Q)是用计算的术语。在一个小样本上尝试两种方法并评估计时(使用 system.time() )以查看是否值得进行子设置以跟踪0。

        2
  •  2
  •   Alex Brown    14 年前

    只需将表达式替换为:

    ifelse(a==0,0,a*exp(b))
    

    如果这能提高性能,我会很惊讶,不过,因为R是解释的,运行 ifelse 可能比浪费 exp 召唤。

        3
  •  1
  •   fabians    14 年前

    类似于DWin的建议:

    > n <- 1e5
    > nonzero <- .01
    > b <- rnorm(n)
    > a <- rep(0, n)
    > a[1:(n*nonzero)] <- rnorm(n*nonzero)
    > 
    > system.time(replicate(100, {
    +                   c <- a*exp(b)
    +               }))
       user      system     elapsed 
       1.19        0.05        1.23 
    > system.time(replicate(100, {
    +                   zero <- a < .Machine$double.eps
    +                   c <- a
    +                   c[!zero] <- a[!zero]*exp(b[!zero])
    +               }))
       user      system     elapsed 
       0.42        0.08        0.50 
    
        4
  •  0
  •   IRTFM    14 年前

    你可以通过对两个向量进行索引来测试你认为浪费的情况。如果该函数比exp花费更多的时间,则可能会产生影响:

    a[ !b==0 ]*exp( b[!b==0] )
    

    还要认识到有陷阱要测试与数值模式是否相等。你可能想把zapsmall和all.equal看作是替代品,这取决于真正的问题是什么。

    > 3/10 == 0.1*3
    [1] FALSE