RcppArmadillo : for 루프의 음수 인덱싱

Sep 02 2020

저는 for()Rcpp를 처음 접했고 RcppArmadillo를 사용하여 루프 에서 음수 인덱싱을 기반으로 계산을 수행하려고합니다 . 나는 이미 RcppArmadillo의 네거티브 인덱싱이 그렇게 간단하지는 않지만 유지되어야하는 요소의 벡터를 통해 수행 될 수 있다는 것을 이미 발견했습니다 (여기에서 찾은 것처럼) . 제거 할 요소가 루핑 인덱스 일 때 그것은 나에게 약간 어려운 것 같습니다. 이 답변 에서 마지막 접근 방식을 구현하려고 시도했지만 성공하지 못했습니다. 루프의 인덱스로 요소를 제외한 요소의 벡터를 지정하는 쉬운 방법이 있습니까?

따라서 y[-i]다음 MWE 에서 RcppArmadillo에서 동등한 항목을 찾으려고합니다 .

# In R:
# Input 
n <- 10
y <- 1:20

# Computation
x <- rep(NA, n)
for(i in 1:n){
x[i] <- sum(y[-i])
}

지금까지 내 코드 Rcpp 코드 :

// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>   

// [[Rcpp::export]]
arma::vec rcpp_sum (arma::vec y, int n){

arma::vec x(n);
arma::vec ind(n);

for (i=0; i<n; i++){
ind[i] = /*no idea...*/
x[i] = sum(y[ind]);
}

return x;
}

어떤 도움이라도 대단히 감사합니다!

답변

2 JosephWood Sep 04 2020 at 05:41

이와 같은 작업의 경우 해당 색인을 건너 뛰는 것이 가장 좋습니다. 표준에서는 C++색인을 확인하고 건너 뜁니다. 이 같은:

// [[Rcpp::export]]
arma::vec rcpp_sum (arma::vec y, int n){
    
    arma::vec x(n);
    
    for (int i = 0; i < n; i++) {
        x[i] = 0; // Initialize value
        
        for (int j = 0; j < y.size(); ++j) {
            if (i != j) {
                x[i] += y[j];
            }
        }
    }
    
    return x;
}

위에서 우리는 설탕 구문에서 멀어지고 있습니다. IMO는 대체가 지나치게 복잡하지 않기 때문에 이와 같은 경우에 괜찮습니다. 단순화하는 동안 RcppArmadillo순수를 사용할 수 있으므로에 대한 종속성 은 필요하지 않습니다.Rcpp

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector pure_rcpp_sum (NumericVector y, int n){
    
    NumericVector x(n);
    
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < y.size(); ++j) {
            if (i != j) {
                x[i] += y[j];
            }
        }
    }
    
    return x;
}

출력 확인 :

all.equal(as.vector(rcpp_sum(y, n)), x)
[1] TRUE

all.equal(pure_rcpp_sum(y, n), x)
[1] TRUE

최신 정보

OP의 요청에 따라 R이러한 특정 목적을 위해 최적화 된 접근 방식 이 있습니다. 위의 내용은에서 하나의 값을 제외하고 벡터의 값만 합산하는 매우 구체적인 문제를 공격하는 방법을 보여줍니다 C++. 이것은 본질적으로 교육적이며이 특정 작업에 대해 반드시 가능한 최선의 방법은 아닙니다 (아래에 표시).

간단한 R코드를 보여주기 전에 내부 루프에 간단한 조건문이 있다는 OP의 우려를 C++두려워해서는 안된다는 점을 지적하고 싶습니다 (base의 경우처럼 R). 내가 알 수 있듯이 OP의 링크에서 설명한 부분 집합은 O (n)이며 추가 논리 벡터의 추가 오버 헤드가 있습니다. 위에서 제안한 솔루션은 기본적으로 추가 객체없이 동일한 작업을 수행하므로 더 효율적이어야합니다.

이제 업데이트 된 코드 :

baseR <- function(y, n) {
    mySum <- sum(y)
    vapply(1:n, function(x) mySum - y[x], FUN.VALUE = 1)    
}

## Here is the OP code for reference
OP <- function(y, n) {
    x <- rep(NA, n)
    for(i in 1:n) {x[i] <- sum(y[-i])}
    x
}

그게 다야. 번개처럼 빠릅니다.

huge_y <- rnorm(1e6)
huge_n <- 1e3

system.time(t1 <- baseR(huge_y, huge_n))
 user  system elapsed 
 0.003   0.000   0.003

system.time(t2 <- pure_rcpp_sum(huge_y, huge_n))
 user  system elapsed 
2.776   0.003   2.779 

system.time(t3 <- OP(huge_y, huge_n))
 user  system elapsed 
9.555   1.248  10.805

all.equal(t1, t2)
[1] TRUE

all.equal(t1, t3)
[1] TRUE