我第一次尝试了Rcpp功能inline,它解决了我的速度问题(感谢Dirk!):
R:将负值替换为零
初始版本看起来像这样:
library(inline)
cpp_if_src <- '
Rcpp::NumericVector xa(a);
int n_xa = xa.size();
for(int i=0; i < n_xa; i++) {
if(xa[i]<0) xa[i] = 0;
}
return xa;
'
cpp_if <- cxxfunction(signature(a="numeric"), cpp_if_src, plugin="Rcpp")
Run Code Online (Sandbox Code Playgroud)
但是当被调用时cpp_if(p),它会p用输出覆盖,这不是预期的.所以我认为它是通过引用传递的.
所以我用以下版本修复它:
library(inline)
cpp_if_src <- '
Rcpp::NumericVector xa(a);
int n_xa = xa.size();
Rcpp::NumericVector xr(a);
for(int i=0; i < n_xa; i++) {
if(xr[i]<0) xr[i] = 0;
}
return xr;
'
cpp_if <- cxxfunction(signature(a="numeric"), cpp_if_src, plugin="Rcpp")
Run Code Online (Sandbox Code Playgroud)
这似乎有效.但是现在,当我将其重新加载到R中时,原始版本不再覆盖其输入(即,相同的确切代码现在不会覆盖其输入):
> cpp_if_src <- '
+ Rcpp::NumericVector xa(a);
+ int n_xa = xa.size();
+ for(int i=0; i < n_xa; i++) {
+ if(xa[i]<0) xa[i] = 0;
+ }
+ return xa;
+ '
> cpp_if <- cxxfunction(signature(a="numeric"), cpp_if_src, plugin="Rcpp")
>
> p
[1] -5 -4 -3 -2 -1 0 1 2 3 4 5
> cpp_if(p)
[1] 0 0 0 0 0 0 1 2 3 4 5
> p
[1] -5 -4 -3 -2 -1 0 1 2 3 4 5
Run Code Online (Sandbox Code Playgroud)
我不是唯一试图复制此行为并发现结果不一致的人:
http://chat.stackoverflow.com/transcript/message/4357344#4357344
这里发生了什么?
Dir*_*tel 21
它们的关键是"代理模型" - 您xa的内存位置与原始对象相同,因此您最终会更改原始内容.
如果您不想这样做,您应该做一件事:使用该clone()方法进行(深度)复制,或者可以显式创建一个新对象,将更改后的对象写入其中.方法二没有这样做,你只需使用两个不同命名的变量,它们都是"指针"(在代理模型意义上)与原始变量.
但是,当您将int向量(从R)传递给NumericVector类型时,另一个复杂因素是隐式转换和复制:它会创建一个副本,然后原始文件不再被更改.
这是一个更明确的示例,类似于我在教程或研讨会中使用的示例:
library(inline)
f1 <- cxxfunction(signature(a="numeric"), plugin="Rcpp", body='
Rcpp::NumericVector xa(a);
int n = xa.size();
for(int i=0; i < n; i++) {
if(xa[i]<0) xa[i] = 0;
}
return xa;
')
f2 <- cxxfunction(signature(a="numeric"), plugin="Rcpp", body='
Rcpp::NumericVector xa(a);
int n = xa.size();
Rcpp::NumericVector xr(a); // still points to a
for(int i=0; i < n; i++) {
if(xr[i]<0) xr[i] = 0;
}
return xr;
')
p <- seq(-2,2)
print(class(p))
print(cbind(f1(p), p))
print(cbind(f2(p), p))
p <- as.numeric(seq(-2,2))
print(class(p))
print(cbind(f1(p), p))
print(cbind(f2(p), p))
Run Code Online (Sandbox Code Playgroud)
这就是我所看到的:
edd@max:~/svn/rcpp/pkg$ r /tmp/ari.r
Loading required package: methods
[1] "integer"
p
[1,] 0 -2
[2,] 0 -1
[3,] 0 0
[4,] 1 1
[5,] 2 2
p
[1,] 0 -2
[2,] 0 -1
[3,] 0 0
[4,] 1 1
[5,] 2 2
[1] "numeric"
p
[1,] 0 0
[2,] 0 0
[3,] 0 0
[4,] 1 1
[5,] 2 2
p
[1,] 0 0
[2,] 0 0
[3,] 0 0
[4,] 1 1
[5,] 2 2
edd@max:~/svn/rcpp/pkg$
Run Code Online (Sandbox Code Playgroud)
因此,无论是传递int-to-float还是float-to-float都非常重要.