我必须为 C++ 编写实现 R 函数。例如,我正在尝试计算滚动 SD,但下面的代码不起作用。任何帮助将不胜感激。 #下面的代码工作正常
library(roll)
n <- 150
x <- rnorm(n)
x
weights <- 0.9 ^ (n:1)
weights
roll_sd(x, width = 5)
#但是当我通过 CPPFunction 传递它时它不起作用
cppFunction("roll_sd(x, width = 5)")
回答1
这不是 cppFunction
的工作方式。您不能简单地将 R 调用传递给它并期望它神奇地转换为 C++。
事实上,它更像是反过来。您用 C++ 编写函数,cppFunction
使该函数在 R 中可用。
与 roll_sd
匹配的滚动标准差的粗略实现如下所示:
cppFunction("NumericVector rolling_sd(NumericVector x, int width) {
NumericVector y = clone(x);
for(int i = 0; i < (int)x.size(); i++) {
if(i < (width - 1)) {
y[i] = NA_REAL;
} else {
double sum = 0.0;
double total = 0.0;
for(int j = i - (width - 1); j <= i; j++) {
sum += x[j];
}
double mean = sum / width;
for(int j = i - (width - 1); j <= i; j++) {
total += pow(x[j] - mean, 2);
}
y[i] = sqrt(total / (width - 1));
}
}
return y;
}")
运行这段代码后,函数 rolling_sd
现在在 R 中可供我们使用,并给出与 roll_sd
相同的结果:
set.seed(1)
x <- rnorm(10)
roll::roll_sd(x, width = 5)
#> [1] NA NA NA NA 0.9610394 1.0022155 1.0183545
#> [8] 0.8694145 0.6229882 0.6688342
rolling_sd(x, width = 5)
#> [1] NA NA NA NA 0.9610394 1.0022155 1.0183545
#> [8] 0.8694145 0.6229882 0.6688342
但是,我们的 C++ 版本要快 10 倍以上,如下面的基准测试所示。
microbenchmark::microbenchmark(roll_sd(x, width = 5), rolling_sd(x, width = 5))
#> Unit: microseconds
#> expr min lq mean median uq max neval cld
#> roll_sd(x, width = 5) 38.7 41.4 44.310 42.2 44.3 154.5 100 b
#> rolling_sd(x, width = 5) 2.1 2.6 3.346 3.3 3.7 15.0 100 a