Rcpp (собственный), повторяющиеся или повторяющиеся строки

#r #eigen #rcpp

#r #eigen #rcpp

Вопрос:

Мне было интересно, есть ли в Rcpp, c или собственном методе дублировать или повторять каждую строку заданной матрицы n раз?

Например, если у меня есть матрица 2 x 2…:

 (1,2
 3,4)
 

… чтобы превратить его в матрицу 4 x 2, например:

 (1,2
 1,2
 3,4
 3,4)
 

Я не нашел ни одного метода или вопроса, подобного этому, в stackoverflow или где-либо в документах Eigen или Rcpp.

Я знаю, что я мог бы использовать цикл for или R-функцию из Rcpp, но я беспокоюсь, что это будет стоить большой производительности.

Кто-нибудь может дать подсказку о том, как это сделать?

РЕДАКТИРОВАТЬ: это кажется простым случаем для R, но оно не работает с большими матрицами, которые приводят к превышению объема памяти. Я все равно передаю данные в скомпилированную функцию Rcpp, поэтому я хотел бы сделать это там.

С уважением, Тим

Комментарии:

1. Я не могу много сказать о части R, но в целом (особенно для Eigen) вам нужно решить, действительно ли вы хотите сохранить повторяющуюся матрицу или просто иметь ленивое выражение «(почти) нулевой стоимости» (это действительно зависит от того, что вы собираетесь делать с этой матрицей).

2. Имейте в виду, что R и Eigen и многие другие системы в целом имеют одну и ту же модель памяти, где вектор (и матрица, рассматриваемая как вектор с 2-мерным измерением) имеют непрерывную память. Таким образом, у вас всегда одна и та же проблема с памятью.

3. Спасибо за это замечание, Дирк! Итак, самым безопасным способом с точки зрения памяти был бы подход Allans снизу?

4. Спасибо @chtz. Можете ли вы уточнить, как я мог бы использовать такое ленивое выражение?

Ответ №1:

Вероятно, для этого вам не нужны Rcpp или Eigen. Следующее векторизовано изначально в R и не требует циклов, поэтому оно должно быть достаточно быстрым.

 mat[rep(seq(nrow(mat)), each = 2),]
#>      [,1] [,2]
#> [1,]    1    2
#> [2,]    1    2
#> [3,]    3    4
#> [4,]    3    4
 

Вы можете немного повысить производительность, написав эквивалент на C , но я был бы удивлен, если бы это имело огромное значение. Если вы сомневаетесь, вы всегда можете профилировать.

Если вам нужна функция Rcpp, которая выполняет то же самое, вы можете попробовать:

 Rcpp::cppFunction("NumericMatrix double_matrix(NumericMatrix m) {
   int nrow = 2 * m.rows();
   NumericMatrix res(nrow, m.ncol());
   for(int i = 0; i < nrow;   i){
     res(i, _) = m((int) i / 2, _);
   }
   return res;
}")
 

Таким образом, вы можете сделать:

 double_matrix(mat)
#>      [,1] [,2]
#> [1,]    1    2
#> [2,]    1    2
#> [3,]    3    4
#> [4,]    3    4
 

Данные

 mat <- matrix(c(1, 3, 2, 4), ncol = 2)

mat
#>      [,1] [,2]
#> [1,]    1    2
#> [2,]    3    4
 

Комментарии:

1. Спасибо, Аллен! Проблема в памяти. Я имею дело с большими матрицами, поэтому любой подход в R постоянно превышает мою оперативную память. Я все равно передаю данные в скомпилированную Rcpp-функцию, поэтому я хотел бы сделать это там, прежде чем выполнять матричные операции с собственным.

2. @timbo1988 смотрите мое обновление. Функция Rcpp в любом случае довольно проста. Конечно, он включает в себя цикл (но цикл должен существовать на каком-то уровне). Вы можете обнаружить, что это быстрее, если вы выполняете итерацию по столбцам, а не по строкам.

3. Вау, спасибо, Аллен! Я обычно стараюсь избегать циклов for , но поскольку они намного быстрее в c , я попробую!

4. Привет, ненавижу вас беспокоить, но что (int) i / 2 делать? Я не знаю, что искать в Google, чтобы найти ответ. 1 и спасибо!

Ответ №2:

Возможно kronecker , это вариант для вас, когда с базой R

 > kronecker(mat, rep(1, 2))
     [,1] [,2]
[1,]    1    2
[2,]    1    2
[3,]    3    4
[4,]    3    4
 

Комментарии:

1. Отличная идея! Никогда не знал об этой функции.