Будет ли пустой список статического размера R cpp более эффективным, чем list.push_back ()? - PullRequest
1 голос
/ 06 августа 2020

Если кто-то хочет перебрать функцию и добавить результаты в список в R cpp, можно использовать метод .push_back(), например:

List appended_list() {
    List emptylist = List::create();
    for (int i = 0; i < 3; i++) {
      emptylist.push_back(i);
    }
    return emptylist;
}

Однако я прав в том, что список каждый раз переопределяется, и поэтому этот метод очень неэффективен? Есть ли способ вместо этого создать список размером c (ie. Создать список из n элементов, где каждый элемент NULL или NA или что-то подобное)? Например, чтобы сделать это в R, нужно написать:

emptylist <- list()
length(emptylist) <- 3
for (i in 1:3) {
  emptylist[[i]] <- i
}

Есть ли способ сделать это в R cpp, пожалуйста? Было бы эффективнее?

Ответы [ 2 ]

4 голосов
/ 06 августа 2020

Предварительно выделенный список будет намного быстрее. Если вы не знаете, как создать список заранее определенного размера, я предлагаю вам, вероятно, потратить некоторое время на вводные материалы R cpp. Вот несколько хороших ресурсов:

Вот пример, показывающий, насколько быстрее можно избежать push_back(). В so.cpp у нас есть

#include <Rcpp.h>

// [[Rcpp::export]]
void test1() {
    Rcpp::List out;
    for ( int i = 0; i < 1000; ++i ) {
        out.push_back(i);
    }
}

// [[Rcpp::export]]
void test2() {
    Rcpp::List out(1000);
    for ( int i = 0; i < 1000; ++i ) {
        out[i] = i;
    }
}

Затем мы сравниваем функции друг с другом:

Rcpp::sourceCpp("so.cpp")
library(microbenchmark)
microbenchmark(empty_list = test1(), pre_allocated = test2())

Unit: microseconds
          expr      min       lq       mean    median        uq      max
    empty_list 3553.549 3755.405 4337.71591 3894.3075 4106.7500 8790.787
 pre_allocated   22.089   23.689   38.67364   24.6645   26.1165 1339.443
 neval
   100
   100

Итак, вы можете видеть, что здесь есть значительная разница. Конечно, в этом упрощенном случае это «значительная» разница, которая не будет заметна для людей, но в более сложном варианте использования или чем-то, что вызывает такую ​​функцию много раз, это может быть на самом деле «значительный».

4 голосов
/ 06 августа 2020

Как правило, вы всегда хотите предварительно выделить.

И да, вы заново открыли кое-что («push_back дорого для типов R SEXP»), которые мы, вероятно, задокументировали близко к десятилетию. Если вы заранее не знаете свой размер, используйте вместо него стандартный контейнер из STL (который имеет намного лучшее поведение, когда дело доходит до роста) и конвертируйте в конце.

...