簡體   English   中英

我如何加快此Rcpp代碼的速度?

[英]How could I speed up this Rcpp code?

我已經在R中實現了一個需要長時間運行的函數。 我已經成功地在R中對其進行了改進,但是現在我想使用Rcpp軟件包來加快它的速度。

我創建了以下Rcpp代碼。 不幸的是,與R代碼運行大約需要相同的時間。 因此,我想對此進行改進。 有誰知道如何改進這段代碼?

非常感謝!

#include <math.h>
#include <Rcpp.h>
using namespace Rcpp;


// [[Rcpp::export]]
double kernelcpp(NumericVector a, NumericVector b, int N){
  int i;
  double sum=0.0;
  for (i=0;i<N;i++){
    if (a[i] > b[i])
      sum+= a[i] - b[i];
    else
      sum+= b[i] - a[i];
  }
  return(exp( - sum));
}
// [[Rcpp::export]]
NumericVector testFromontcpp(NumericMatrix z1, NumericMatrix z2, int Nbootstrap){
  // first element of TKeps = TK
  int i,j,k,t;
  int dim1 = z1.nrow();
  int dim2 = z2.nrow();
  double n1 = (double) dim1;
  double n2 = (double) dim2;
  int dimension = z1.ncol();
  int N = dim1 + dim2;
  NumericVector TKeps(Nbootstrap+1);
  Rcpp::NumericMatrix bb(N,N);

  double cc = 1 / (n1*n2*(n1+n2-2));
  double a = sqrt(1/(n1*n1-n1)-cc);
  double b = - sqrt(1/(n2*n2-n2)-cc);

  for (i=0 ; i<N ; i++){
    for (j=0 ; j<N ; j++){
    if (i != j){
      if (i < dim1) {
        if (j < dim1){
          bb(i,j) = kernelcpp(z1(i,_),z1(j,_),dimension);
        } else {
          bb(i,j) = kernelcpp(z1(i,_),z2(j-dim1,_),dimension);
        }
      }
      else{
        if (j < dim1){
          bb(i,j) = kernelcpp(z2(i-dim1,_),z1(j,_),dimension);
        } else {
          bb(i,j) = kernelcpp(z2(i-dim1,_),z2(j-dim1,_),dimension);
        }
      }
    }
    }
  }

  TKeps(0)=0.0;
  for (i=0 ; i<N ; i++){
    for (j=0 ; j<N ; j++){
    if (i != j){
      if (i < dim1) {
        if (j < dim1){
          TKeps(0) += bb(i,j)* (a*a + cc);
        } else {
          TKeps(0) += bb(i,j) * (a*b + cc);
        }
      }
      else{
        if (j < dim1){
          TKeps(0) += bb(i,j) * (a*b + cc);
        } else {
          TKeps(0) += bb(i,j) * (b*b + cc);
        }
      }
    }
    }
  }


  for (k=1 ; k<=Nbootstrap ; k++){
    TKeps(k)=0;
    int R[N];
    for (i = 0 ; i < N ; i++)
      R[i] = i;
    for (i = 0; i < N - 1 ; i++) {
      int j = i + rand() / (RAND_MAX / (N - i) + 1);
      t = R[j];
      R[j] = R[i];
      R[i] = t;
    }

    for (i=0 ; i<N ; i++){
      for (j=0 ; j<N ; j++){
        if (i != j){ 
          if (R[i] < n1) {
            if (R[j] < n1){
              TKeps(k) += bb(i,j) * (a*a + cc);
            } else {
              TKeps(k) += bb(i,j) * (a*b + cc);
            }
          } else{
            if (R[j] < n1){
              TKeps(k) += bb(i,j) * (b*a + cc);
            } else {
              TKeps(k) += bb(i,j) * (b*b + cc);
            }
          }
        }
      }
    }
  }
  return(TKeps);
}

由於我不完全了解您的代碼的功能,因此我可以從頭開始看到兩件事:

  • 您從R環境調用的函數是testFromontcpp(...)。 我建議該函數應將SEXP值作為參數。 這些S表達式是指向R的內存的指針。如果您不使用SEXP,則兩個矩陣都將被復制:考慮一個1000x1000的矩陣,這意味着您有100萬個R中保存的條目,這些條目被復制到C ++。 為此,請寫:

    testFromontcpp(SEXP x,SEXP y,SEXP z){

    NumericMatrix z1(x),z2(y);

    int * Nbootstrap = INTEGER(z);

    ...}

注意:在for循環中,您不能使用i<Nbootstrap 您必須寫i<*Nbootstrap !!!

  • 其次……更重要:由於R的矩陣被保存為指向列的指針,而從列的指針被保存為行,因此C的矩陣被另存為。 我要說的是,跳入內存並一直跳回而不是遵循內存路徑會花費很多。 我的建議是:切換for循環,因此首先遍歷特定列的行,而不要反過來。

到最后一點:在大學里的一項工作中,我也遇到了遍歷矩陣的問題。 在我的情況下,轉置矩陣然后進行計算要便宜得多。

希望能對您有所幫助。

最好,邁克爾

PS:談到第1點...我只是通過實現和使用SEXP對您的代碼進行了基准測試。 使用SEXP時,對於100x100矩陣(隨機數介於1到10之間),速度會稍快一些。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM