2014-07-16 2 views
1

R에서 실행하기가 오래 걸리는 함수를 구현했습니다. 나는 R에서 그것을 향상시키는 데 성공했지만 지금은 Rcpp 패키지를 사용하여 더 빠르게하려고합니다.어떻게이 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); 
} 
+0

'kernelcpp '는 여러 번 호출되기 때문에 인라인 함수로 정의 할 수 있습니다. 얼마나 큰 차이가 있을지 모르지만 시도하고보기는 쉽습니다. 일반적으로 함수 호출은 제자리에서 명령문을 실행하는 것보다 느립니다. – Backlin

+1

먼저 코드를 프로파일 링하여 어떤 라인이 가장 많은 시간을 차지하는 지 확인하십시오. 그러면 개선해야 할 부분을 알게 될 것입니다. –

+0

Rcpp 함수에서 프로파일 링을 수행 할 수 있습니까? – Pop

답변

4

, 나는 처음부터 두 가지를 볼 수 있습니다 : 당신이 당신의 R 환경에서 호출

  • 기능은 testFromontcpp입니다 (...). 이 함수는 매개 변수로 SEXP 값을 가져야합니다. 이러한 S-Expressions은 R의 메모리에 대한 포인터입니다. SEXP를 사용하지 않으면 두 행렬 모두 복사됩니다. 1000x1000 행렬을 고려하면 R에 저장된 항목이 1 백만 개이며 C++에 복사됩니다. 그래서 연락 할 :

    testFromontcpp (SEXP의 X, Y의 SEXP, SEXP의 z) {

    NumericMatrix Z1 (X), (Z2) (Y);

    int * Nbootstrap = INTEGER (z);

    ... }

조심 다음에 대한 루프에서 당신은 i<Nbootstrap을 사용할 수 없습니다. 당신은 i<*Nbootstrap를 작성해야합니다 !!!

  • 두 번째로 중요한 점 : R의 행렬이 열 포인터와 행 포인터에서 행에 저장되므로 C 행렬은 다른 방식으로 저장됩니다. 제가 말하고자하는 것은 메모리 경로를 따르는 대신에 메모리로 건너 뛰고 전체 시간으로 되돌아가는 것이 많은 비용이 든다는 것입니다. 이에 대한 제안은 다음과 같습니다. for-loops를 전환하십시오. 먼저 특정 열의 행을 반복하고 다른 행은 반복하지 마십시오.

마지막 지점까지 : 대학의 과제에서 행렬 반복에 대한 문제도있었습니다. 내 경우에는 행렬을 조 변경 한 다음 계산을하는 것이 더 저렴했습니다.

도와 드리겠습니다.

최저

, 마이클

PS : 포인트 1을 참조하면 ... 난 그냥 당신의 구현 및 SEXP를 사용하여 코드를 벤치마킹. SEXP를 사용하면 1에서 10 사이의 난수를 갖는 100x100 행렬에 대해 약간 더 빠릅니다.

+0

고마워요!귀하의 조언과 함께, 내 코드 실행 시간은 이제 두로 나누었습니다 : – Pop

+0

당신은 오신 것을 환영합니다! 내가 너를 도울 수있어서 기뻐. :) 아마도 코드를 자세히 살펴볼 시간이 더있을 것입니다. 그건 그렇고 : 행렬의 행/열을 함수에 전달할 때마다 모든 요소가 매번 복사됩니다. 어쩌면 그 행/열을 벡터로 "감싸고"(포인터와 같은) 벡터의 참조를 전달하는 것이 도움이 될 것입니다. – Mike

+0

네, 그렇게하려고했습니다;) – Pop

관련 문제