我一直在尝试RcppArrayFire软件包,主要是重写RcppArmadillo的一些成本函数,似乎无法克服"没有从'af::array'到'float'的可行转换。 我也遇到了一些后端错误,下面的示例似乎没有这些错误。
这个 cov-var 示例写得很差,只是为了使用我实际成本函数中的所有相关编码片段。 截至目前,它是"RcppArrayFire.package.skeleton"生成的软件包中唯一的添加物。
#include "RcppArrayFire.h"
#include <Rcpp.h>
// [[Rcpp::depends(RcppArrayFire)]]
// [[Rcpp::export]]
float example_ols(const RcppArrayFire::typed_array<f32>& X_vect, const RcppArrayFire::typed_array<f32>& Y_vect){
int Len = X_vect.dims()[0];
int Len_Y = Y_vect.dims()[0];
while( Len_Y < Len){
Len --;
}
float mean_X = af::sum(X_vect)/Len;
float mean_Y = af::sum(Y_vect)/Len;
RcppArrayFire::typed_array<f32> temp(Len);
RcppArrayFire::typed_array<f32> temp_x(Len);
for( int f = 0; f < Len; f++){
temp(f) = (X_vect(f) - mean_X)*(Y_vect(f) - mean_Y);
temp_x(f) = af::pow(X_vect(f) -mean_X, 2);
}
return af::sum(temp)/af::sum(temp_x);
}
/*** R
X <- 1:10
Y <- 2*X +rnorm(10, mean = 0, sd = 1)
example_ols(X, Y)
*/
首先要考虑的是af::sum
函数,它有不同的形式:一个在设备内存中返回af::array
的sf::sum(af::array)
和一个在主机内存中返回T
的模板化af::sum<T>(af::array)
。因此,对示例的最小更改是使用af::sum<float>
:
#include "RcppArrayFire.h"
#include <Rcpp.h>
// [[Rcpp::depends(RcppArrayFire)]]
// [[Rcpp::export]]
float example_ols(const RcppArrayFire::typed_array<f32>& X_vect,
const RcppArrayFire::typed_array<f32>& Y_vect){
int Len = X_vect.dims()[0];
int Len_Y = Y_vect.dims()[0];
while( Len_Y < Len){
Len --;
}
float mean_X = af::sum<float>(X_vect)/Len;
float mean_Y = af::sum<float>(Y_vect)/Len;
RcppArrayFire::typed_array<f32> temp(Len);
RcppArrayFire::typed_array<f32> temp_x(Len);
for( int f = 0; f < Len; f++){
temp(f) = (X_vect(f) - mean_X)*(Y_vect(f) - mean_Y);
temp_x(f) = af::pow(X_vect(f) -mean_X, 2);
}
return af::sum<float>(temp)/af::sum<float>(temp_x);
}
/*** R
set.seed(1)
X <- 1:10
Y <- 2*X +rnorm(10, mean = 0, sd = 1)
example_ols(X, Y)
*/
但是,还有更多可以改进的地方。排名不分先后:
- 您不需要包含
Rcpp.h
。 - 有一个用于计算
af::array
平均值的af::mean
函数。 - 通常,只有将数组从 R 获取到 C++ 时才需要
RcppArrayFire::typed_array<T>
。在C++和返回的路上,您可以使用af::array
. - 即使您的设备不支持
double
,您仍然可以在主机上使用double
值。 - 为了获得良好的性能,您应该避免
for
循环并使用矢量化函数,就像在 R 中一样。不过,你必须对X
和Y
施加相等的维度。
有趣的是,当我使用矢量化函数时,我得到了不同的结果。现在我不确定为什么会这样,但以下表格对我来说更有意义。您应该验证结果是否是您想要获得的结果:
#include <RcppArrayFire.h>
// [[Rcpp::depends(RcppArrayFire)]]
// [[Rcpp::export]]
double example_ols(const RcppArrayFire::typed_array<f32>& X_vect,
const RcppArrayFire::typed_array<f32>& Y_vect){
double mean_X = af::mean<double>(X_vect);
double mean_Y = af::mean<double>(Y_vect);
af::array temp = (X_vect - mean_X) * (Y_vect - mean_Y);
af::array temp_x = af::pow(X_vect - mean_X, 2.0);
return af::sum<double>(temp)/af::sum<double>(temp_x);
}
/*** R
set.seed(1)
X <- 1:10
Y <- 2*X +rnorm(10, mean = 0, sd = 1)
example_ols(X, Y)
*/
顺便说一句,更短的版本是:
#include <RcppArrayFire.h>
// [[Rcpp::depends(RcppArrayFire)]]
// [[Rcpp::export]]
af::array example_ols(const RcppArrayFire::typed_array<f32>& X_vect,
const RcppArrayFire::typed_array<f32>& Y_vect){
return af::cov(X_vect, Y_vect) / af::var(X_vect);
}
通常,尽可能多地使用内置函数是个好主意。