2014-11-19 3 views
6

Ho un frame di dati che è principalmente zeri qualcosa di simile aR - dati frame - convertire matrici sparse

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

I dati effettivi è di circa 90.000 righe con 10.000 elementi (struttura dati sparsi?). Posso convertirlo in una matrice sparsa? Mi aspetto di guadagnare tempo ed efficienze spaziali utilizzando una matrice sparsa invece di una cornice dati.

Qualsiasi aiuto sarebbe apprezzato

Update # 1: Ecco il codice per generare il frame di dati. Grazie Richard per aver fornito questo

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

Il codice non funziona per me. Sono i 'row.names', credo. – pjvandehaar

risposta

3

Quanto è sparsa la tua matrice? Questo determina come migliorare le sue dimensioni.

La matrice di esempio ha 3 1 se 6 0 s. Con quel rapporto, c'è poco risparmio di spazio ingenuamente usando 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, questo potrebbe risolvere il problema ... ma sarebbe bello se tu potessi * modificare la tua risposta * e fornire una piccola spiegazione su come e perché funziona :) Non dimenticare - ci sono un mucchio di neofiti su Stack overflow, e potrebbero imparare una o due cose dalla tua esperienza - ciò che è ovvio per te potrebbe non essere così per loro. –

+0

La performance è stata pessima, quindi ho cancellato il mio codice originale. – pjvandehaar

+0

Il frame di dati originale ha circa 30.000 righe e 2000 colonne – Abhi

3

Si potrebbe fare la prima colonna in nomi di fila, quindi utilizzare Matrix dal pacchetto 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 

dove il frame di dati x originale è

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

Richard, grazie per aver pubblicato la soluzione. Domanda veloce però, perché hai spostato i nomi dalla prima colonna ai nomi delle righe? – Abhi

+0

Beh, non sono ancora sicuro di come farlo altrimenti. Ma se può essere fatto, modifico per mostrare che (o qualcun altro pubblicherà una risposta più adatta). –

7

potrebbe essere un po 'più efficiente della memoria (ma più lenta) per evitare di copiare tutti i dati in una fitta matrice:

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 

Se si dispone di memoria sufficiente, è necessario utilizzare la risposta di Richard, ovvero trasformare data.frame in una matrice densa e utilizzare Matrix.

3

Lo faccio tutto il tempo ed è un rompicapo, quindi ho scritto un metodo per questo chiamato sparsify() nel mio pacchetto R - mltools. Funziona su data.table s che sono solo fantasia data.frames.


per risolvere il tuo problema specifico ...

Installare mltools (o semplicemente copiare il metodo sparsify() nell'ambiente)

pacchetti Load

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 

In generale, il metodo sparsify() è piuttosto flessibile. Ecco alcuni esempi di come è possibile utilizzarlo:

Effettuare alcuni dati.i tipi di dati Avviso e scelta dei fattori utilizzati

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 Usa

> 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  . 

Converti AN a 0 e Sparsify Them

> 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  . 

generano Colonne che identificano i valori 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 

Generare colonne che identificano NA valori nel modo efficiente La maggior parte di memoria

> 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

Super utile, grazie mille per il tuo lavoro! –