«Проблема слишком велика» при попытке сохранить dgCMatrix в формате csv в R

#r

Вопрос:

Я пытаюсь конвертировать файл RDS, содержащий разреженную матрицу (dgCMatrix) Я получил от коллеги в обычный текстовый CSV-файл. Я понимаю, что этот файл будет иметь размер во много гигабайт, не нужно меня предупреждать. Я пробовал использовать as.matrix, но получаю ошибку «проблема слишком велика». Как я могу этого избежать?

 > write.csv(as.matrix(x), 'table.csv')
Loading required package: Matrix
Error in asMethod(object) : 
  Cholmod error 'problem too large' at file ../Core/cholmod_dense.c, line 105
 

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

1. Каковы размеры матрицы, dim(x) ?

2. Это 50281×82151

3. Это примерно 30,8 ГБ памяти для плотной версии вашей матрицы. При chunk = 100 строках по умолчанию за проход моей функции ниже потребуется 62,7 МБ плотной матрицы за проход, чтобы она могла работать.

Ответ №1:

Почему бы не обработать разреженную матрицу по частям? Приведенный ниже код — это способ сделать это.

 library(Matrix)

write_sparse_csv <- function(x, file, ..., chunk = 100){
  passes <- nrow(x) %/% chunk
  remaining <- nrow(x) %% chunk
  if(passes > 0){
    inx <- seq_len(chunk)
    y <- x[inx, , drop = FALSE]
    y <- as.matrix(y)
    write.table(y, file, append = FALSE, sep = ",", col.names = !is.null(colnames(x)), ...)
    passes <- passes - 1L
    for(i in seq_len(passes)){
      inx <- inx   chunk
      y <- x[inx, , drop = FALSE]
      y <- as.matrix(y)
      write.table(y, file, append = TRUE, sep = ",", col.names = FALSE,  ...)
    }
    if(remaining > 0){
      inx <- inx   remaining
      y <- x[inx, , drop = FALSE]
      y <- as.matrix(y)
      write.table(y, file, append = TRUE, sep = ",", col.names = FALSE, ...)
    }
  } else if(remaining > 0){
    inx <- seq_len(remaining)
    y <- x[inx, , drop = FALSE]
    y <- as.matrix(y)
    write.table(y, file, append = FALSE, sep = ",", col.names = FALSE, ...)
  }
}

set.seed(2021)
n <- 1e6
M <- Matrix(sample(c(rep(0, 9*n/10), seq_len(n/10))), ncol = 5e2, sparse = TRUE)
dim(M)

write_sparse_csv(M, "~/tmp/test.csv")