【问题标题】:Optimize/vectorize a loop in R that generates randoms from ranges in input vectors?优化/矢量化 R 中的循环,从输入向量的范围生成随机数?
【发布时间】:2016-02-26 04:36:29
【问题描述】:

问题:

我在 R 中使用循环从两个(“父”)向量创建一个新向量,为新向量中的每个位置生成一个随机值,该值在父级在该位置的值范围内(用于genetic algorithm 中的交叉阶段)。请注意,我不想要 x 和 y 的平均值,而是在各个位置的值范围内的随机值。

示例代码:

x = c(0.1, 0.7, 1, 0.8)
y = c(0, 0.9, 0.2, 1)
child = rep(NA, length(x))
for(i in 1:length(x)){
  child[i] = sample(seq(min(x[i], y[i]),  
                        max(x[i],y[i]), by=0.01), 1)
}
# This might yield, for example: 0.02 0.83 0.73 0.88 

问题:

它工作得很好,但我想也许有一种更有效的方法来做到这一点(因为我需要在数千次迭代中为 100-1000 个人执行此操作)。 在 R 中,有很好的快速函数,如 ifelsecolMeansmax.colmatchrollmean 等,它们适用于向量,所以我想知道,有没有类似的东西适合我的目的也是? (据我所知,apply 帮派可能在这里帮不上什么忙)。或者这样的循环真的是我能做的最好的吗?

【问题讨论】:

    标签: r loops vector vectorization genetic-algorithm


    【解决方案1】:

    我们可以使用runif 从均匀分布中获取随机数,并使用pmaxpmin 对最小值和最大值进行向量化:

    round(runif(length(x), pmin(x, y), pmax(x, y)), 2)
    

    一个小基准:

    library(microbenchmark)
    
    set.seed(42)
    x <- runif(1000)
    y <- runif(1000)
    
    microbenchmark(vectorize ={round(runif(length(x), pmin(x, y), pmax(x, y)), 2)},
                   mapply =  {mapply(runif, 1, pmin(x, y), pmax(x, y))},
                   lapply = {unlist(lapply(seq_along(x), function(p, q, i) { sample(seq(min(p[i], q[i]), max(p[i],q[i]), by=0.01), 1) }, p=x, q=y))})
    
    Unit: microseconds
          expr       min        lq       mean     median        uq       max neval cld
     vectorize   316.417   321.026   341.6501   336.0015   342.914   529.154   100 a  
        mapply  4311.559  4429.640  4733.0420  4543.6875  4806.535  9935.631   100  b 
        lapply 46987.459 47718.980 50484.6058 48474.5015 53599.756 60043.093   100   c
    

    【讨论】:

    • @jeremycg: res &lt;- round(runif(length(x), pmin(x, y), pmax(x, y)), 2); table(pmin(x,y)&lt;=res); table(pmax(x,y)&gt;=res) 显示某些值超出范围...令人惊讶。
    • @fishtank 它的舍入误差 - 例如 p(min x, y) 可能是 0.232,我们得到的随机数是 0.234,它被舍入到 0.23,我们超出了范围。在这种情况下,op 仅使用 2 位数字作为输入,因此无需担心(更广泛地说,不要四舍五入到低于您的输入)。
    • 无论如何都不需要舍入部分;我只是在示例中使用了简单的“短”数字来保持它,嗯,简单。除了是一个很好的答案之外,很高兴看到与以前的“最新技术”进行比较。
    【解决方案2】:

    这是mapply 解决方案:

    mapply(runif, 1, pmin(x,y), pmax(x,y))
    

    (尽管@jeremycg 的解决方案表明您不需要 *apply 函数,并且也可以将 runif 的最小值和最大值矢量化。)

    【讨论】:

      【解决方案3】:

      这是一个在 2 秒内包含 1000 万条记录的 data.table 解决方案:

      library(data.table)
      set.seed(4444)
      n <- 10000000
      system.time({
        dt <- data.table(x=runif(n=n,min=0,max=10),y=runif(n=n,min=0,max=10))
        dt[,child := runif(n=n,min=pmin(x,y),max=pmax(x,y)),by=.I]
      })
      dt
      
      #user  system elapsed 
      #2.01    0.03    2.06 
      

      【讨论】:

      • 也是个好主意。但我选择了@jeremycg 的答案,因为它似乎更适合我的目的(示例中的向量几乎就是我正在使用的)。
      猜你喜欢
      • 1970-01-01
      • 2016-02-11
      • 1970-01-01
      • 2020-07-17
      • 2012-06-11
      • 2019-09-16
      • 2020-06-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多