在 R 中的大向量中设置元素
Setting elements in a big vector in R
我在 R 中使用向量,存储 bigz 对象 (GMP package)。当向量不是太大(最多 200 个元素)时它工作正常,但是当向量增长时,性能会急剧下降。
为了找到瓶颈所在,我使用 profvis
库执行我的程序,我发现问题出在下一段代码:
res <- as.bigz(rep(0, length(resT))) #resT is a list of bigz of length 600
res[[1]] <- sum.bigz(a_bigz_elem, another_bigz_elem)
i <- 1
while (i <= length(resT) - 1) {
res[[i + 1]] <- sum.bigz(resT[[i + 1]], resE[[i + 1]])
i <- i + 1
}
更具体地说,在第 5 行(列表中的元素赋值)。
我知道这个解决方案比增长向量更好,即 res <- c(res, sum.bigz(resT[[i + 1]], resE[[i + 1]]))
,但我很确定有更有效的方法来完成分配。
我已经阅读了 SO 中的相关 post 和 Advanced R 参考文档,但没有任何提高我的表现的方法。知道如何改进吗?
有
res <- as.bigz(rep(0, length(resT))) #resT is a list of bigz of length 600
您不是创建list
。当您将其更改为:
res <- as.list(as.bigz(rep(0, length(resT))))
您创建了一个列表,执行时间应该会减少。
一个可重现的例子如下:
library(gmp)
resT <- as.list(urand.bigz(600, seed=0))
resE <- as.list(urand.bigz(600, seed=1))
a_bigz_elem <- resT[[1]]
another_bigz_elem <- resE[[1]]
res <- as.list(as.bigz(rep(0, length(resT))))
res[[1]] <- sum.bigz(a_bigz_elem, another_bigz_elem)
i <- 1
while (i <= length(resT) - 1) {
res[[i + 1]] <- sum.bigz(resT[[i + 1]], resE[[i + 1]])
i <- i + 1
}
这里有一个简洁的方法,比@GKi的方案效率高一点:
mapply(sum.bigz, resT, resE, SIMPLIFY = FALSE)
基准:
library(gmp)
resT_list <- as.list(urand.bigz(1000, seed=0))
resE_list <- as.list(urand.bigz(1000, seed=1))
f1 <- function(){
a_bigz_elem <- resT_list[[1]]
another_bigz_elem <- resE_list[[1]]
res <- as.list(as.bigz(rep(0, length(resT_list))))
res[[1]] <- sum.bigz(a_bigz_elem, another_bigz_elem)
i <- 1
while (i <= length(resT_list) - 1) {
res[[i + 1]] <- sum.bigz(resT_list[[i + 1]], resE_list[[i + 1]])
i <- i + 1
}
res
}
f2 <- function(){
mapply(sum.bigz, resT_list, resE_list, SIMPLIFY = FALSE)
}
library(microbenchmark)
microbenchmark(
f1 = f1(),
f2 = f2(),
times = 10
)
# Unit: milliseconds
# expr min lq mean median uq max neval cld
# f1 15.27488 16.48450 19.84019 17.51613 25.25338 28.10120 10 b
# f2 11.83838 12.21875 13.30705 12.87080 14.37143 15.75504 10 a
我在 R 中使用向量,存储 bigz 对象 (GMP package)。当向量不是太大(最多 200 个元素)时它工作正常,但是当向量增长时,性能会急剧下降。
为了找到瓶颈所在,我使用 profvis
库执行我的程序,我发现问题出在下一段代码:
res <- as.bigz(rep(0, length(resT))) #resT is a list of bigz of length 600
res[[1]] <- sum.bigz(a_bigz_elem, another_bigz_elem)
i <- 1
while (i <= length(resT) - 1) {
res[[i + 1]] <- sum.bigz(resT[[i + 1]], resE[[i + 1]])
i <- i + 1
}
更具体地说,在第 5 行(列表中的元素赋值)。
我知道这个解决方案比增长向量更好,即 res <- c(res, sum.bigz(resT[[i + 1]], resE[[i + 1]]))
,但我很确定有更有效的方法来完成分配。
我已经阅读了 SO 中的相关 post 和 Advanced R 参考文档,但没有任何提高我的表现的方法。知道如何改进吗?
有
res <- as.bigz(rep(0, length(resT))) #resT is a list of bigz of length 600
您不是创建list
。当您将其更改为:
res <- as.list(as.bigz(rep(0, length(resT))))
您创建了一个列表,执行时间应该会减少。
一个可重现的例子如下:
library(gmp)
resT <- as.list(urand.bigz(600, seed=0))
resE <- as.list(urand.bigz(600, seed=1))
a_bigz_elem <- resT[[1]]
another_bigz_elem <- resE[[1]]
res <- as.list(as.bigz(rep(0, length(resT))))
res[[1]] <- sum.bigz(a_bigz_elem, another_bigz_elem)
i <- 1
while (i <= length(resT) - 1) {
res[[i + 1]] <- sum.bigz(resT[[i + 1]], resE[[i + 1]])
i <- i + 1
}
这里有一个简洁的方法,比@GKi的方案效率高一点:
mapply(sum.bigz, resT, resE, SIMPLIFY = FALSE)
基准:
library(gmp)
resT_list <- as.list(urand.bigz(1000, seed=0))
resE_list <- as.list(urand.bigz(1000, seed=1))
f1 <- function(){
a_bigz_elem <- resT_list[[1]]
another_bigz_elem <- resE_list[[1]]
res <- as.list(as.bigz(rep(0, length(resT_list))))
res[[1]] <- sum.bigz(a_bigz_elem, another_bigz_elem)
i <- 1
while (i <= length(resT_list) - 1) {
res[[i + 1]] <- sum.bigz(resT_list[[i + 1]], resE_list[[i + 1]])
i <- i + 1
}
res
}
f2 <- function(){
mapply(sum.bigz, resT_list, resE_list, SIMPLIFY = FALSE)
}
library(microbenchmark)
microbenchmark(
f1 = f1(),
f2 = f2(),
times = 10
)
# Unit: milliseconds
# expr min lq mean median uq max neval cld
# f1 15.27488 16.48450 19.84019 17.51613 25.25338 28.10120 10 b
# f2 11.83838 12.21875 13.30705 12.87080 14.37143 15.75504 10 a