使用R,我想知道迭代评估多个输入和输出函数的最佳方法是什么。我受到了http://paulbourke.net/fractals/clifford/
所见情节的激励关键等式是:
x_{n+1} = sin(A* y_n) + C* cos(A* x_n)
y_{n+1} = sin(B* x_n) + D* cos(B* y_n)
我想存储每次迭代的结果。我猜测有一种比通过以下代码中描述的循环更快的方式:
#Parameters
A <- -1.4
B <- 1.6
C <- 1.0
D <- 0.7
n_iter <- 10000000
#Initial values
x0 <- 0
y0 <- 0
#function to calculate n+1 points
cliff <- function(x,y){
c(sin(A*y) + C*cos(A*x), sin(B*x) + D*cos(B*y))
}
#matrix to store results
res_mat <- matrix(0,nrow=n_iter,ncol=2)
#recursive loop (definitely not the fastest way to do this?)
for (i in 2:n_iter){
res_mat[i,] <- cliff(res_mat[i-1,1],res_mat[i-1,2])
}
我想这实际上并不是一个单独的函数,而是2对彼此的输出进行操作。任何有关评估这些功能的更合适方法的见解将不胜感激。我敢说我会从一些一般的编程建议中受益,这些建议不一定是R特定的。
答案 0 :(得分:4)
一种选择是使用Rcpp;对于像这样的迭代函数,每个新值都是前一个迭代值的复杂函数,这通常会产生相当好的加速。
library(Rcpp)
cliff.rcpp = cppFunction("
NumericMatrix cliff(int nIter, double A, double B, double C, double D) {
NumericMatrix x(nIter, 2);
for (int i=1; i < nIter; ++i) {
x(i,0) = sin(A*x(i-1,1)) + C*cos(A*x(i-1,0));
x(i,1) = sin(B*x(i-1,0)) + D*cos(B*x(i-1,1));
}
return x;
}")
cliff.rcpp(10, 1, 2, 3, 4)
# [,1] [,2]
# [1,] 0.0000000 0.0000000
# [2,] 3.0000000 4.0000000
# [3,] -3.7267800 -0.8614156
# [4,] -3.2595913 -1.5266964
# [5,] -3.9781665 -4.2182644
# [6,] -1.1296464 -3.1953775
# [7,] 1.3346977 3.2046776
# [8,] 0.6386906 4.4230487
# [9,] 1.4501988 -2.3914781
# [10,] -0.3208062 0.5208984
我们可以看到这会将相同的结果返回给问题中的代码:
cliff.orig <- function(n_iter, A, B, C, D) {
#function to calculate n+1 points
cliff <- function(x,y){
c(sin(A*y) + C*cos(A*x), sin(B*x) + D*cos(B*y))
}
#matrix to store results
res_mat <- matrix(0,nrow=n_iter,ncol=2)
#recursive loop (definitely not the fastest way to do this?)
for (i in 2:n_iter){
res_mat[i,] <- cliff(res_mat[i-1,1],res_mat[i-1,2])
}
res_mat
}
identical(cliff.rcpp(10, 1, 2, 3, 4), cliff.orig(10, 1, 2, 3, 4))
# [1] TRUE
对于原始问题中的输入,Rcpp方法产生~50倍的加速:
system.time(cliff.rcpp(10000000, -1.4, 1.6, 1.0, 0.7))
# user system elapsed
# 0.661 0.046 0.717
system.time(cliff.orig(10000000, -1.4, 1.6, 1.0, 0.7))
# user system elapsed
# 34.591 0.245 35.040