Преобразуйте подпредставление arma::cube в NumericVector, чтобы использовать сахар
Я передал 3D-массив из 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 ответ
У вас есть несколько вариантов здесь:
- Вы можете просто использовать функцию Armadillo для этого, функцию-член
.index_min()
(см. документацию Armadillo здесь). - Ты можешь использовать
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;
}
У нас есть одна функция, которая использует Armadillo .index_min()
и тот, который использует 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
Создано в 2018-12-21 пакетом представлением (v0.2.1)