0

我在 R 和 Rcpp 中都编写了一个函数,它基本上只接受数据集 x、尺度参数 gamma 和向量参数 beta,因此返回拟合概率。以下是我在 R 中的代码:

tp_predict<-function(x,gamma,beta){
  n<-nrows(x)
  x<-as.matrix(cbind(1,x))
  vec<-x%*%beta
  In<-vec<0
  Ip<-!vec<0
  vecN<-vec[In]
  vecP<-vec[Ip]
  fitted<-vector(,n)
  t<-tanh(gamma)
  b<-t+1
  a<-1-t
  fitted[In]<-b/(exp(-vecN/b)+1)
  fitted[Ip]<-a/(exp(-vecP/a)+1)+t
  fitted<-as.vector(fitted)
  return(fitted)
}

在 Rcpp 中:

arma::vec tp_predict_c(arma::mat x,double gamma,arma::vec beta){
  int n = x.n_rows;
  arma::vec one(n, fill::ones);
  arma::mat xx=join_rows(one,x);
  arma::vec v = xx * beta;
  arma::uvec In = find (v<0);
  arma::uvec Ip = find (v>=0); 
  arma::vec vecN = v.elem(In);
  arma::vec vecP = v.elem(Ip);
  double t = tanh(gamma);
  double a = 1-t;
  double b = 1+t;
  arma::vec fitted(n);
  fitted.elem(In)=b/(exp(-vecN/b)+1);
  fitted.elem(Ip)=a/(exp(-vecP/a)+1)+t;
  
  return fitted;
}

测试数据 x 是使用 rmvnorm() 从多正态分布生成的。在低维度(10 列)和小数据大小(1000 行)中,Rcpp 代码比 R 代码效果更好

Unit: microseconds
                           expr  min    lq    mean median    uq     max neval
   tp_predict(x = X, 0.3, Beta) 62.1 63.85 173.640   65.5 66.85 10868.9   100
 tp_predict_c(x = X, 0.3, Beta) 30.7 31.15  40.714   31.9 32.75   781.6   100

但是如果我将大小增加到 100000(维度仍然是 10),则 Rcpp 代码会比 R 慢:

Unit: milliseconds
                           expr    min      lq     mean  median     uq      max neval
   tp_predict(x = X, 0.3, Beta) 5.8967 6.15060 8.477195 6.21560 6.7766 131.9571   100
 tp_predict_c(x = X, 0.3, Beta) 8.6547 8.82975 9.102348 9.01935 9.2005  12.6010   100

此外,如果我将维度增加到 100 并且大小保持为 1000,则 Rcpp 函数的性能不如低维度:

Unit: microseconds
                           expr   min    lq    mean median    uq   max neval
   tp_predict(x = X, 0.3, Beta) 188.7 197.0 204.745 201.85 206.5 280.5   100
 tp_predict_c(x = X, 0.3, Beta) 166.1 171.1 189.729 181.20 189.9 511.0   100

当尺寸和大小增加时,看起来 Rcpp 函数的 cpu 时间比 R 扩展得更快。我是 Rcpp 的新手,我只是直接将我的 R 代码翻译成 Rcpp。我不确定我是否做了一些愚蠢的事情,我也不知道为什么会这样。我能做些什么来解决这个问题吗?

4

1 回答 1

0

您的代码正在将给定的向量和矩阵复制到函数的入口处tp_predict_c(),这是低效且不需要的。

默认情况下,C++“按值”传递对象,这意味着“复制这个对象”。您需要通过“通过引用”传递每个对象来告诉编译器避免复制。

要通过引用传递,只需将函数的定义更改为:

arma::vec tp_predict_c(const arma::mat& x, double gamma, const arma::vec& beta)

注意 and 中的const关键字和&字符。const arma::mat&const arma::vec&

告诉编译器这个const对象不会被修改,&告诉编译器通过引用传递。这两者都允许进行额外的优化。

于 2020-08-17T01:34:16.397 回答