我正在编写一个函数,该函数需要迭代地调用作为参数传递给列表的每个元素的函数g
。
我想知道如何使其尽可能快。我可以使用Rcpp
和特定种类的g
(用Cpp编写所有内容)来达到可接受的速度,但是我不知道是否可以通过将R函数用作参数来达到类似的速度。
正在做一些测试以找出R变慢的原因并发现了一些意想不到的结果:
minus <- function(x) -x
minus_vec <- Vectorize(minus, "x")
使用一些简单的函数来反转符号进行测试。
f0 <- function(x) {
sapply(x, minus)
}
f1 <- function(x) {
for(i in seq_along(x)){
x[i] <- -x[i]
}
x
}
f2 <- function(x) {
for(i in seq_along(x)){
x[i] <- minus(x[i])
}
x
}
我得到以下结果:
a <- 1:10^5
library(rbenchmark)
benchmark(f0(a), f1(a), f2(a), minus_vec(a), minus(a))[,c(1,4)]
test relative
1 f0(a) 454.842
2 f1(a) 25.579
3 f2(a) 178.211
4 minus_vec(a) 523.789
5 minus(a) 1.000
我想对以下几点进行一些解释:
为什么f1
和f2
的速度不一样?当他们做完全相同的事情时,编写代码-x[i]
和调用函数minus(x[i])
真的应该是如此不同吗?
为什么f0
比f2
慢?我一直认为apply
函数比for
循环更有效,但从来没有真正理解为什么,现在我什至找到了一个反例。
是否可以使用函数f1
来使函数的运行速度与minus
一样快?
为什么对minus
进行矢量化(由于-
已经被矢量化,所以不必要,但是不一定总是如此)使它变得如此糟糕?
答案 0 :(得分:2)
不是完整的答案,但是这里有一些注意事项
1 minus(x)
与-x
:无所事事总比做某事好
您的函数minus
调用`-`
,因此添加的步骤会增加计算时间。老实说,我不知道具体是谁,什么时候,什么时候,换句话说,我不知道应该有多少计算时间。
下面是一个突出显示它的示例:我们有四个函数,所有的平方都是数字
fa <- function (n) n^2
fb <- function (n) fa(n)
fc <- function (n) fb(n)
fd <- function (n) fc(n)
Fa <- function (n) {
for (i in seq_along(n)) n[i] <- fa(i)
n
}
Fb <- function (n) {
for (i in seq_along(n)) n[i] <- fb(i)
n
}
Fc <- function (n) {
for (i in seq_along(n)) n[i] <- fc(i)
n
}
Fd <- function (n) {
for (i in seq_along(n)) n[i] <- fd(i)
n
}
这是基准测试结果
n <- 1:10^4
b <- benchmark(Fa(n),Fb(n),Fc(n),Fd(n), replications = 1000L)
b
# test replications elapsed relative user.self sys.self user.child sys.child
# 1 Fa(n) 1000 3.93 1.000 3.85 0.00 NA NA
# 2 Fb(n) 1000 7.08 1.802 6.94 0.02 NA NA
# 3 Fc(n) 1000 10.16 2.585 9.94 0.06 NA NA
# 4 Fd(n) 1000 13.68 3.481 13.56 0.00 NA NA
# looks rather even
diff(b$elapsed)
# [1] 3.15 3.08 3.52
现在返回您的minus
功能
a <- 1:10^5
b <- benchmark(f0(a), f1(a), f2(a), minus_vec(a), minus(a))
b$elapsed[b$test == 'f2(a)'] - b$elapsed[b$test == 'f1(a)']
# [1] 3.39
2 :apply
vs for
vs Vectorize
:
@NavyCheng提供了有关该主题的一些很好的材料。现在我的理解是,apply
系列(就像Vectorize
一样)在R
中循环(而如果我没有误会`-`
的循环是在{{1 }})。
同样,我不知道确切的细节,但是如果C
使用apply/Vectorize
循环,那么从理论上讲(实际上是经常),编写适当的R
循环,其效果会更好或更好。
3 功能与 for
一样快:
是临时的,我的结局是使用f1
软件包通过作弊进行的。 (作弊,因为首先要在Rcpp
中编写函数)
在 C ++
中c++
现在使用#include <RcppArmadillo.h>
//[[Rcpp::depends(RcppArmadillo)]]
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector minusCpp(NumericVector x) {
for (int k = 0; k < x.length(); ++k) {
x[k] = -x[k];
}
return x;
}
中的标记标记
R
答案 1 :(得分:1)
忽略 -x [i] 和 minus(-x [i]),我将四个问题总结为两个:
第一个问题:
apply 功能旨在方便阅读, 不一定很快。
和 apply 系列将比 forloop ,
同样,sapply函数首先使用as.vector(unlist(...))将任何内容转换为向量,最后尝试将答案简化为合适的形式。
对于第二个问题,这是因为 Vectorize 是 mapply 的包装,如果您在Rstudio中输入Vectorize
,则会看到详细代码。您可以阅读this以获得更多帮助。