Эффективно сохранять индексы ненулевых элементов матрицы в файл

Мне нужно сохранить индексы ненулевых элементов матрицы в файл. Это очень хорошо работает для матриц небольшого размера, сохраняя номера строк ненулевых индексов в a и номера столбцов ненулевых индексов в b:

X <- matrix(c(1,0,3,4,0,5), byrow=TRUE, nrow=2);    
a <- row(X)[which(!X == 0)]
b <- col(X)[which(!X == 0)]

Но размер матрицы огромен, и мне нужно найти эффективный способ сохранить индексы в файл txt, чтобы у меня было a[1] b[1] (новая строка) a[2] b[2] и скоро. Какие-либо предложения?


person wthimdh    schedule 18.11.2015    source источник


Ответы (2)


В пакете Matrix есть отличное решение для очень больших матриц. Объект sparseMatrix можно обобщить в data.frame, где i и j — ваши индексы, а x — значение:

X <- matrix(c(1,0,3,4,0,5), byrow=TRUE, nrow=2);    
a <- row(X)[which(!X == 0)]
b <- col(X)[which(!X == 0)]

library(Matrix)
Y <- Matrix(X, sparse = TRUE)
(res <- summary(Y))
  2 x 3 sparse Matrix of class "dgCMatrix", with 4 entries 
    i j x
  1 1 1 1
  2 2 1 4
  3 1 3 3
  4 2 3 5
class(res)
  [1] "sparseSummary" "data.frame"   

Затем вы можете подмножить, чтобы получить только i и j:

res[, c("i", "j")] 
   i j
 1 1 1
 2 2 1
 3 1 3
 4 2 3
person mlegge    schedule 18.11.2015

Вы можете захватить строки и столбцы всех ненулевых местоположений, используя which с параметром arr.ind=TRUE, записывая результат в файл с write.table:

write.table(which(X != 0, arr.ind=TRUE), "file.txt", row.names=F, col.names=F)

Это дает разделенные пробелами выходные данные пар элементов в указанном файле:

1 1
2 1
1 3
2 3

Использование which с arr.ind=TRUE экономит несколько сканирований вашей входной матрицы по сравнению с кодом, размещенным в вашем вопросе, поэтому расчет данных для вывода должен быть немного быстрее. Вы можете увидеть это на бенчмарке для большей матрицы (1000 x 1000, с плотностью 1%):

set.seed(144)
bigX <- matrix(sample(c(rep(0, 99), 1), 1000000, replace=T), nrow=1000)
OP <- function(X) cbind(row(X)[which(!X == 0)], col(X)[which(!X == 0)])
josilber <- function(X) which(X != 0, arr.ind=TRUE)

library(microbenchmark)
microbenchmark(OP(bigX), josilber(bigX))
# Unit: milliseconds
#            expr       min        lq      mean    median        uq      max neval
#        OP(bigX) 20.513535 23.014517 36.463423 25.354250 59.130520 65.50304   100
#  josilber(bigX)  3.873165  4.281624  6.741824  5.250777  6.998415 45.02542   100

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

person josliber♦    schedule 18.11.2015