2014-11-19 4 views
6

У меня есть кадр данных, который является в основном нули что-то похожее наR - данные кадра - преобразовать в разреженную матрицу

name,factor_1,factor_2,factor_3 
ABC,1,0,0 
DEF,0,1,0 
GHI,0,0,1 

Фактические данные о 90 000 строк с 10000 объектов (разреженный кадр данных?). Могу ли я преобразовать это в разреженную матрицу? Я ожидаю получить экономию времени и пространства за счет использования разреженной матрицы вместо кадра данных.

Любая помощь будет оценена

Update # 1: Вот код для генерации кадра данных. Спасибо Ричарду за предоставление этого

x <- structure(list(name = structure(1:3, .Label = c("ABC", "DEF", "GHI"), 
        class = "factor"), 
       factor_1 = c(1L, 0L, 0L), 
       factor_2 = c(0L,1L, 0L), 
       factor_3 = c(0L, 0L, 1L)), 
       .Names = c("name", "factor_1","factor_2", "factor_3"), 
       class = "data.frame", 
       row.names = c(NA,-3L)) 
+0

Ваш код не работает для меня. Думаю, это «row.names». – pjvandehaar

ответ

3

Насколько редкая ваша матрица? Это определяет, как улучшить размер.

Ваш пример матрицы имеет 3 1 s и 6 0 s. С этим соотношением наименьшая экономия места достигается наивно с помощью Matrix.

> library('pryr') # for object_size 
> library('Matrix') 
> m <- matrix(rbinom(9e4*1e4, 1, 1/3), ncol = 1e4) 
> object_size(m) 
3.6 GB 
> object_size(Matrix(m, sparse = T)) 
3.6 GB 
+1

Hiya, это вполне может решить проблему ... но было бы хорошо, если бы вы могли * отредактировать свой ответ * и дать небольшое объяснение о том, как и почему это работает :) Не забудьте - есть кучи новичков на Переполнение стека, и они могли бы узнать кое-что из вашего опыта - что очевидно для вас, возможно, не так для них. –

+0

Производительность была плохая, поэтому я удалил свой исходный код. – pjvandehaar

+0

Исходный фрейм данных имеет около 30 000 строк и 2000 столбцов – Abhi

3

Вы могли бы сделать первый столбец в названиях строк, а затем использовать Matrix из Matrix пакета.

rownames(x) <- x$name 
x <- x[-1] 
library(Matrix) 
Matrix(as.matrix(x), sparse = TRUE) 
# 3 x 3 sparse Matrix of class "dtCMatrix" 
#  factor_1 factor_2 factor_3 
# ABC  1  .  . 
# DEF  .  1  . 
# GHI  .  .  1 

, где исходный кадр x данные

x <- structure(list(name = structure(1:3, .Label = c("ABC", "DEF", 
"GHI"), class = "factor"), factor_1 = c(1L, 0L, 0L), factor_2 = c(0L, 
1L, 0L), factor_3 = c(0L, 0L, 1L)), .Names = c("name", "factor_1", 
"factor_2", "factor_3"), class = "data.frame", row.names = c(NA, 
-3L)) 
+0

Ричард благодарит за публикацию решения. Быстрый вопрос, почему, почему вы перенесли имена из первого столбца в имена строк? – Abhi

+0

Ну, я не уверен, как это сделать в противном случае. Но если это можно сделать, я отредактирую, чтобы показать, что (или кто-то другой опубликует более подходящий ответ). –

7

Это может быть немного больше памяти эффективным (но медленнее), чтобы избежать копирования всех данных в плотную матрицу:

y <- Reduce(cbind2, lapply(x[,-1], Matrix, sparse = TRUE)) 
rownames(y) <- x[,1] 

#3 x 3 sparse Matrix of class "dgCMatrix" 
#   
#ABC 1 . . 
#DEF . 1 . 
#GHI . . 1 

Если у вас достаточно памяти, вы должны использовать ответ Ричарда, т. Е. Превратить ваш data.frame в плотную матрицу и использовать Matrix.

3

Я делаю это все время, и это боль в прикладе, поэтому я написал метод для него под названием sparsify() в моей R-упаковке - mltools. Он работает на data.table s, которые просто причудливые data.frames.


Чтобы решить конкретную проблему ...

Установите mltools (или просто скопировать метод sparsify() в вашей среде)

Загружайте пакеты

library(data.table) 
library(Matrix) 
library(mltools) 

Sparsify

x <- data.table(x) # convert x to a data.table 
sparseM <- sparsify(x[, !"name"]) # sparsify everything except the name column 
rownames(sparseM) <- x$name # set the rownames 

> sparseM 
3 x 3 sparse Matrix of class "dgCMatrix" 
    factor_1 factor_2 factor_3 
ABC  1  .  . 
DEF  .  1  . 
GHI  .  .  1 

В целом, метод sparsify() является довольно гибким. Вот несколько примеров того, как вы можете использовать его:

Сделайте некоторые данные.Типы Примечание данные и неиспользуемые уровни фактора

dt <- data.table(
    intCol=c(1L, NA_integer_, 3L, 0L), 
    realCol=c(NA, 2, NA, NA), 
    logCol=c(TRUE, FALSE, TRUE, FALSE), 
    ofCol=factor(c("a", "b", NA, "b"), levels=c("a", "b", "c"), ordered=TRUE), 
    ufCol=factor(c("a", NA, "c", "b"), ordered=FALSE) 
) 
> dt 
    intCol realCol logCol ofCol ufCol 
1:  1  NA TRUE  a  a 
2:  NA  2 FALSE  b NA 
3:  3  NA TRUE NA  c 
4:  0  NA FALSE  b  b 

Out-Of-The-Box Использование

> sparsify(dt) 
4 x 7 sparse Matrix of class "dgCMatrix" 
    intCol realCol logCol ofCol ufCol_a ufCol_b ufCol_c 
[1,]  1  NA  1  1  1  .  . 
[2,]  NA  2  .  2  NA  NA  NA 
[3,]  3  NA  1 NA  .  .  1 
[4,]  .  NA  .  2  .  1  . 

Преобразование Nas в 0s и Sparsify Их

> sparsify(dt, sparsifyNAs=TRUE) 
4 x 7 sparse Matrix of class "dgCMatrix" 
    intCol realCol logCol ofCol ufCol_a ufCol_b ufCol_c 
[1,]  1  .  1  1  1  .  . 
[2,]  .  2  .  2  .  .  . 
[3,]  3  .  1  .  .  .  1 
[4,]  .  .  .  2  .  1  . 

Generate Столбцы, определяющие значения NA

> sparsify(dt[, list(realCol)], naCols="identify") 
4 x 2 sparse Matrix of class "dgCMatrix" 
    realCol_NA realCol 
[1,]   1  NA 
[2,]   .  2 
[3,]   1  NA 
[4,]   1  NA 

Сформировать столбцы, содержащие NA значения В эффективно Большинство памяти

> sparsify(dt[, list(realCol)], naCols="efficient") 
4 x 2 sparse Matrix of class "dgCMatrix" 
    realCol_NotNA realCol 
[1,]    .  NA 
[2,]    1  2 
[3,]    .  NA 
[4,]    .  NA 
+0

Супер полезно, большое спасибо за вашу работу! –