Преобразуйте подпредставление arma :: cube в NumericVector, чтобы использовать сахар - PullRequest
0 голосов
/ 21 декабря 2018

Я передаю трехмерный массив из R в C ++ и столкнулся с проблемами преобразования типов.Как мы можем преобразовать arma::cube subviews из RcppArmadillo в NumericVectors, чтобы работать с ними, используя сахарные функции из Rcpp, такие как which_min?

Скажем, у вас есть 3D-куб Q с некоторыми числовыми записями.Моя цель - получить индекс минимального значения записей столбцов для каждой строки i и для каждого третьего измерения k.В синтаксисе R это which.min(Q[i,,k]).

Например, для i = 1 и k = 1

cube Q = randu<cube>(3,3,3);
which_min(Q.slice(1).row(1)); // this fails

Я думал, что преобразование в NumericVector поможет, но это преобразование не удается

which_min(as<NumericVector>(Q.slice(1).row(1))); // conversion failed

Как мне заставить это работать?Спасибо за вашу помощь.

1 Ответ

0 голосов
/ 21 декабря 2018

У вас есть несколько вариантов:

  1. Для этого вы можете просто использовать функцию Armadillo, функцию-член .index_min() (см. Документацию Armadillo здесь ).
  2. Вы можете использовать Rcpp::wrap(), который "преобразует произвольный объект в SEXP" , чтобы превратить arma::cube subviews в Rcpp::NumericVector и использовать функцию сахара Rcpp::which_min().

Первоначально у меня был только первый вариант ответа, поскольку он кажется более простым способом достижения вашей цели, но я добавляю второй вариант (в обновлении к ответу), поскольку теперь я считаю, что это произвольнопреобразования могут быть частью того, что вам интересно.

Я поместил следующий код C ++ в файл so-answer.cpp:

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

// [[Rcpp::export]]
Rcpp::List index_min_test() {
    arma::cube Q = arma::randu<arma::cube>(3, 3, 3);
    int whichmin = Q.slice(1).row(1).index_min();
    Rcpp::List result = Rcpp::List::create(Rcpp::Named("Q") = Q,
                                           Rcpp::Named("whichmin") = whichmin);
    return result;
}

// [[Rcpp::export]]
Rcpp::List which_min_test() {
    arma::cube Q = arma::randu<arma::cube>(3, 3, 3);
    Rcpp::NumericVector x = Rcpp::wrap(Q.slice(1).row(1));
    int whichmin = Rcpp::which_min(x);
    Rcpp::List result = Rcpp::List::create(Rcpp::Named("Q") = Q,
                                           Rcpp::Named("whichmin") = whichmin);
    return result;
}

У нас есть одна функция, которая использует * 1024 от Armadillo* и тот, который использует Rcpp::wrap(), чтобы разрешить использование Rcpp::which_min().

Затем я использую Rcpp::sourceCpp(), чтобы скомпилировать его, сделать функции доступными для R и продемонстрировать вызов их с несколькими различными семенами.:

Rcpp::sourceCpp("so-answer.cpp")
set.seed(1)
arma <- index_min_test()
set.seed(1)
wrap <- which_min_test()
arma$Q[2, , 2]
#> [1] 0.2059746 0.3841037 0.7176185
wrap$Q[2, , 2]
#> [1] 0.2059746 0.3841037 0.7176185
arma$whichmin
#> [1] 0
wrap$whichmin
#> [1] 0
set.seed(2)
arma <- index_min_test()
set.seed(2)
wrap <- which_min_test()
arma$Q[2, , 2]
#> [1] 0.5526741 0.1808201 0.9763985
wrap$Q[2, , 2]
#> [1] 0.5526741 0.1808201 0.9763985
arma$whichmin
#> [1] 1
wrap$whichmin
#> [1] 1
library(microbenchmark)
microbenchmark(arma = index_min_test(), wrap = which_min_test())
#> Unit: microseconds
#>  expr    min      lq     mean  median      uq    max neval cld
#>  arma 12.981 13.7105 15.09386 14.1970 14.9920 62.907   100   a
#>  wrap 13.636 14.3490 15.66753 14.7405 15.5415 64.189   100   a

CreaТед 2018-12-21 по представлению пакета (v0.2.1)

...