Optimize/vectorize R 中从输入向量的范围生成随机数的循环?
Optimize/vectorize a loop in R that generates randoms from ranges in input vectors?
问题:
我在 R 中使用一个循环从两个 ("parent") 个向量创建一个新向量,为新向量中的每个位置生成一个随机值,该值在父向量的值范围内处于这个位置(这是 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 中,有一些很好的快速函数,如 ifelse
、colMeans
、max.col
、match
, rollmean
等,它们适用于向量,所以我想知道,是否有一些东西对我来说也是这样吗? (据我所知,apply
团伙在这里可能帮不上什么忙)。或者像这样的循环真的是我能做的最好的吗?
我们可以使用 runif
从均匀分布中获取随机数,并使用 pmax
和 pmin
向量化最小值和最大值:
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
这是一个 mapply
解决方案:
mapply(runif, 1, pmin(x,y), pmax(x,y))
(尽管@jeremycg 的解决方案表明您不需要 *apply 函数并且也可以对 runif
的最小值和最大值进行向量化。)
这是一个 data.table 解决方案,在 2 秒内处理 1000 万条记录:
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
问题:
我在 R 中使用一个循环从两个 ("parent") 个向量创建一个新向量,为新向量中的每个位置生成一个随机值,该值在父向量的值范围内处于这个位置(这是 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 中,有一些很好的快速函数,如 ifelse
、colMeans
、max.col
、match
, rollmean
等,它们适用于向量,所以我想知道,是否有一些东西对我来说也是这样吗? (据我所知,apply
团伙在这里可能帮不上什么忙)。或者像这样的循环真的是我能做的最好的吗?
我们可以使用 runif
从均匀分布中获取随机数,并使用 pmax
和 pmin
向量化最小值和最大值:
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
这是一个 mapply
解决方案:
mapply(runif, 1, pmin(x,y), pmax(x,y))
(尽管@jeremycg 的解决方案表明您不需要 *apply 函数并且也可以对 runif
的最小值和最大值进行向量化。)
这是一个 data.table 解决方案,在 2 秒内处理 1000 万条记录:
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