Чередование результатов многих объектов в Rcpp - PullRequest
0 голосов
/ 26 апреля 2018

Мне нужно записать в файл строку за строкой матриц и разреженных матриц, которые появляются в списке, и я делаю что-то вроде этого:

#include <RcppArmadillo.h>

// [[Rcpp::export]]
bool write_rows (Rcpp::List data, Rcpp::CharacterVector clss, int n) {

  int len = data.length();
  for(int i = 0; i<n; i++) {
    for(int j=0; j<len; j++) {
      if (clss[j] == "matrix") {
        Rcpp::NumericMatrix x = data[j];
        auto row = x.row(i);
        // do something with row i
      } else if (clss[j] == "dgCMatrix") {
        arma::sp_mat x = data[j];
        auto row = x.row(i);
        // do something different with row i
      }
    }
  }

  return true;
}

Эта функция может быть вызвана в R с помощью:

data <- list(
  x = Matrix::rsparsematrix(nrow = 1000, ncol = 1000, density = 0.3), 
  y = matrix(1:10000, nrow = 1000, ncol = 10)
  )

clss <- c("dgCMatrix", "matrix")

write_rows(data, clss, 1000)

Функция получает список матриц или разреженных матриц с одинаковым количеством строк и записывает эти матрицы строка за строкой, т.е.сначала записывает первые строки всех элементов в data, затем во второй ряд всех элементов и т. д.

Моя проблема в том, что кажется, что эта строка arma::sp_mat x = data[i]; оказывает огромное влияние на производительность, так как кажется,что я неявным образом приводим элемент списка data[j] к разреженной матрице броненосца n раз.

Мой вопрос: есть ли в любом случае, я мог бы избежать этого?Есть ли более эффективное решение?Я пытался найти решение, изучая исходный код readr, поскольку они также записывают элементы списка построчно, но они также выполняют приведение для каждой строки ( в этой строке, например, , номожет это не влияет на производительность, потому что они имеют дело с SEXPS?

1 Ответ

0 голосов
/ 26 апреля 2018

С уточнением кажется, что результат должен чередовать строки из каждой матрицы.Вы по-прежнему можете делать это, избегая многократных преобразований.

Это оригинальный код, модифицированный для создания некоторого фактического вывода:

// [[Rcpp::export]]
arma::mat write_rows(Rcpp::List data, Rcpp::CharacterVector clss, int nrows, int ncols) {

    int len = data.length();
    arma::mat result(nrows*len, ncols);

    for (int i = 0, k = 0; i < nrows; i++) {
        for (int j = 0; j < len; j++) {
            arma::rowvec r;

            if (clss[j] == "matrix") {
                Rcpp::NumericMatrix x = data[j];
                r = x.row(i);
            }
            else {
                arma::sp_mat x = data[j];
                r = x.row(i);
            }

            result.row(k++) = r;
        }
    }

    return result;
}

Следующий код создает вектор преобразованных объектов, а затемизвлекает строки из каждого объекта по мере необходимости.Преобразование выполняется только один раз для каждой матрицы.Я использую структуру, содержащую плотный и разреженный мат, потому что это намного проще, чем иметь дело с объединениями;и я не хочу перетаскивать boost::variant или требовать C ++ 17.Поскольку есть только 2 класса, с которыми мы хотим иметь дело, накладные расходы минимальны.

struct Matrix_types {
    arma::mat m;
    arma::sp_mat M;
};

// [[Rcpp::export]]
arma::mat write_rows2(Rcpp::List data, Rcpp::CharacterVector clss, int nrows, int ncols) {

    const int len = data.length();
    std::vector<Matrix_types> matr(len);
    std::vector<bool> is_dense(len);
    arma::mat result(nrows*len, ncols);

    // populate the structs
    for (int j = 0; j < len; j++) {
        is_dense[j] = (clss[j] == "matrix");
        if (is_dense[j]) {
            matr[j].m = Rcpp::as<arma::mat>(data[j]);
        }
        else {
            matr[j].M = Rcpp::as<arma::sp_mat>(data[j]);
        }
    }

    // populate the result
    for (int i = 0, k = 0; i < nrows; i++) {
        for (int j = 0; j < len; j++, k++) {
            if (is_dense[j]) {
                result.row(k) = matr[j].m.row(i);
            }
            else {
                arma::rowvec r(matr[j].M.row(i));
                result.row(k) = r;
            }
        }
    }

    return result;
}

Выполнение некоторых тестовых данных:

data <- list(
    a=Matrix(1.0, 1000, 1000, sparse=TRUE),
    b=matrix(2.0, 1000, 1000),
    c=Matrix(3.0, 1000, 1000, sparse=TRUE),
    d=matrix(4.0, 1000, 1000)
)

system.time(z <- write_rows(data, sapply(data, class), 1000, 1000))
#   user  system elapsed 
# 185.75   35.04  221.38 

system.time(z2 <- write_rows2(data, sapply(data, class), 1000, 1000))
#   user  system elapsed 
#   4.21    0.05    4.25 

identical(z, z2)
# [1] TRUE
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...