#c #r #vector #vectorization #rcpp
#c #r #векторный #векторизация #rcpp
Вопрос:
Я пытаюсь заставить переработку векторов работать в Rcpp.
> recycle_and_add <- Rcpp::cppFunction("
NumericVector recycle_and_add(NumericVector x, NumericVector y) {
return x y;
}")
> recycle_and_add(42, 1:5)
[1] 43
Я ожидаю, что он вернет что-то вроде
> 42 1:5
[1] 43 44 45 46 47
После некоторого анализа я выяснил, что это x.size()
есть 1
и y.size()
находится 5
внутри функции Rcpp, поэтому очевидно, что векторная переработка не работает «из коробки».
Хотя я могу вручную найти самый длинный из x
и y
и переработать более короткий, в реальном приложении есть 3 или 4 аргумента, требующих переработки, поэтому я могу представить, что ручная прокрутка приведет к множеству переменных, указывающих на разные векторы, и превратит код в кучу спагетти.
Имеет ли Rcpp какую-либо встроенную поддержку для переработки векторов, например, с добавлением сахара?
Комментарии:
1. Разверните свои векторы в R перед вызовом на C . Самый простой способ сделать это — вызвать
data.frame
.2. Перечитайте некоторую документацию. Вы ошибочно полагаете, что Rcpp волшебным образом переработается за вас. Когда вы передаете 42 в
NumericVector
вы получаете именно это: одноэлементный числовой вектор, содержащий 42.3. Вы можете использовать
rep_len()
, как в R.4. @HongOoi Спасибо, это звучит просто, но я не уверен, что снижение производительности незначительно. Также просто для записи, вы предлагаете мне использовать
df <- data.frame(arg1=arg1, arg2=arg2)
, а затем.Call("_myPackage_myFunction", df$arg1, df$arg2)
?
Ответ №1:
С точки зрения стратегии почти всегда проще переработать в R, а затем перейти на C .
Если это должно выполняться на C , то должен работать следующий шаблон проектирования:
#include <Rcpp.h>
// [[Rcpp::export]]
Rcpp::NumericVector recycle_vector(Rcpp::NumericVector x,
Rcpp::NumericVector y) {
// Obtain vector sizes
int n_x = x.size();
int n_y = y.size();
// Check both vectors have elements
if(n_x <= 0 || n_y <= 0) {
Rcpp::stop("Both `x` and `y` vectors must have at least 1 element.");
}
// Compare the three cases that lead to recycling...
if(n_x == n_y) {
return x y;
} else if (n_x > n_y) {
return Rcpp::rep_len(y, n_x) x;
}
return Rcpp::rep_len(x, n_y) y;
}
Тестовые примеры:
recycle_vector(1:3, 1:3)
# [1] 2 4 6
recycle_vector(4, 1:3)
# [1] 5 6 7
recycle_vector(10:12, -2:-1)
# [1] 8 10 10