2011-08-23 23 views
6

Supongamos que tengo una matriz realmente grande de datos dispersos, pero solo me interesa ver una muestra que la haga aún más dispersa. Supongamos que también tengo un marco de datos de tripletas que incluye columnas para fila/columna/valor de los datos (importados de un archivo csv). Sé que puedo utilizar la matriz dispersa() la función de biblioteca (Matrix) para crear una matriz dispersa utilizandoAgregando valores a una matriz usando vectores de índice que incluyen nombres de fila y columna

sparseMatrix(i=df$row,j=df$column,x=df$value) 

Sin embargo, a causa de mis valores termino con una matriz dispersa que es millones de filas de decenas de miles de columnas (la mayoría de ellas están vacías porque mi subconjunto excluye la mayoría de las filas y columnas). Todas esas filas y columnas cero terminan desviando algunas de mis funciones (por ejemplo, la agrupación en clúster: termino con un clúster que incluye el origen cuando el origen ni siquiera es un punto válido). Me gustaría realizar la misma operación, pero usando i y j como rownames y colnames. He intentado crear un vector densa, el muestreo de hasta el tamaño máximo y la adición de valores utilizando

denseMatrix <- matrix(0,nrows,ncols,dimnames=c(df$row,df$column)) 
denseMatrix[as.character(df$row),as.character(df$column)]=df$value 

(De hecho, he estado fijando es igual a 1, porque no estoy interesado en el valor en este caso) pero he estado encontrando que llena toda la matriz porque toma la cruz de todas las filas y columnas en lugar de solo row1 * col1, row2 * col2 ... ¿Alguien sabe una manera de lograr lo que intento? ¿hacer? Alternativamente, estaría bien rellenar una matriz dispersa y simplemente desechar de alguna manera todas las filas y columnas cero para compactarla en una forma más densa (pero me gustaría mantener alguna referencia a los números originales de filas y columnas) ¡Agradezco cualquier sugerencia!

He aquí un ejemplo:

> rows<-c(3,1,3,5) 
> cols<-c(2,4,6,6) 
> mtx<-sparseMatrix(i=rows,j=cols,x=1) 
> mtx 
5 x 6 sparse Matrix of class "dgCMatrix" 

[1,] . . . 1 . . 
[2,] . . . . . . 
[3,] . 1 . . . 1 
[4,] . . . . . . 
[5,] . . . . . 1 

me gustaría deshacerse de las columnas 1,3 y 5, así como las filas 2 y 4. Este es un ejemplo bastante trivial, pero imagino que si en lugar de tener los números de fila 1, 3 y 5 eran 1000, 3000 y 5000. Entonces habría muchas más filas vacías entre ellos. Esto es lo que sucede cuando el uso de una matriz densa con el nombre filas/columnas

> dmtx<-matrix(0,3,3,dimnames=list(c(1,3,5),c(2,4,6))) 
> dmtx 
    2 4 6 
1 0 0 0 
3 0 0 0 
5 0 0 0 
> dmtx[as.character(rows),as.character(cols)]=1 
> dmtx 
    2 4 6 
1 1 1 1 
3 1 1 1 
5 1 1 1 
+0

¿Puedes mostrar un pequeño ejemplo, digamos 10x10, matriz dispersa, más los trillizos que podrías usar en esa situación, y qué subconjunto deseas? –

+1

¿Has investigado el paquete SparseM? – Spacedman

+0

Estoy agregando un ejemplo sobre – dscheffy

Respuesta

4

Cuando se dice "deshacerse de" ciertas columnas/filas, lo que significa que sólo esta:

> mtx[-c(2,4), -c(1,3,5)] 
3 x 3 sparse Matrix of class "dgCMatrix" 

[1,] . 1 . 
[2,] 1 . 1 
[3,] . . 1 

obras de subdivisión, ¿así que solo necesita una forma de averiguar qué filas y columnas están vacías? Si eso es correcto, puede usar colSums() y rowSums() ya que estos se han mejorado mediante el paquete Matrix para tener los métodos apropiados para matrices dispersas. Esto debe preservar la poca densidad durante la operación

> dimnames(mtx) <- list(letters[1:5], LETTERS[1:6]) 
> mtx[which(rowSums(mtx) != 0), which(colSums(mtx) != 0)] 
3 x 3 sparse Matrix of class "dgCMatrix" 
    B D F 
a . 1 . 
c 1 . 1 
e . . 1 

o, quizás más seguro

> mtx[rowSums(mtx) != 0, colSums(mtx) != 0] 
3 x 3 sparse Matrix of class "dgCMatrix" 
    B D F 
a . 1 . 
c 1 . 1 
e . . 1 
+0

tu solución domina la mía, he eliminado la mía ... –

4

Su código casi funciona, sólo tiene que cbind juntos los nombres de las filas y nombres de columna. Cada fila de la matriz resultante se trata como un par en lugar de tratar las filas y las columnas por separado.

> dmtx <- matrix(0,3,3,dimnames=list(c(1,3,5),c(2,4,6))) 
> dmtx[cbind(as.character(rows),as.character(cols))] <- 1 
> dmtx 
    2 4 6 
1 0 1 0 
3 1 0 1 
5 0 0 1 

Esto puede ser más rápido si se usan factores.

> rowF <- factor(rows) 
> colF <- factor(cols) 
> dmtx <- matrix(0, nlevels(rowF), nlevels(colF), 
       dimnames=list(levels(rowF), levels(colF))) 
> dmtx[cbind(rowF,colF)] <- 1 
> dmtx 
    2 4 6 
1 0 1 0 
3 1 0 1 
5 0 0 1 

También puede utilizar estos factores en una llamada a sparseMatrix.

> sparseMatrix(i=as.integer(rowF), j=as.integer(colF), x=1, 
+    dimnames = list(levels(rowF), levels(colF))) 
3 x 3 sparse Matrix of class "dgCMatrix" 
    2 4 6 
1 . 1 . 
3 1 . 1 
5 . . 1 

Tenga en cuenta que una de las otras soluciones puede ser más rápida; la conversión a factores puede ser lenta si hay una gran cantidad de datos.

+0

Drat, no debí haber vacilado tanto, ¡solo me ganaste! – joran

+0

Gracias! Las páginas de ayuda son geniales cuando buscas una función, no tan útil cuando es la sintaxis básica del núcleo ... Ahora lo entiendo, dos vectores te darán una submatriz: estaba apuntando a la submatriz que está llena matriz. Es bueno saber que unir los dos vectores esencialmente me permitirá vectorizar la operación. Todavía lo sé por R, pero estoy aprendiendo rápidamente ... – dscheffy

1

Su primer problema se debe al hecho de que el coordinate list (COO) tiene valores no contiguos para los índices de fila y columna. Cuando me enfrento a esto, o incluso cuando trato con la mayoría de las matrices dispersas, tiendo a reordenar las filas y columnas por su apoyo.

Puede hacerlo de dos maneras:

  1. producen la matriz dispersa y al hacerlo colSums y rowSums de logical(yourMatrix) para obtener los valores de apoyo, o
  2. Usar una función como table o bigtabulate (desde el bigmemory suite) para calcular el n. ° de veces únicas en que se ha producido cada valor en la lista de coordenadas. (Mi preferencia es bigtabulate.)

Una vez que tenga el apoyo, puede utilizar la función rank (en realidad, rank(-1 * support, ties = "first")) para asignar los índices originales a los nuevos, basados ​​en sus filas.

En este punto, si crea la matriz con sparseMatrix, solo producirá una matriz con dimensiones tales que todas sus filas y columnas tengan soporte. No se asignará a nada más grande.

Esto es similar al enfoque de @GavinSimpson, aunque su método solo elimina las filas y columnas faltantes, mientras que mi enfoque se reordena para poner la densidad máxima en la esquina superior izquierda de la matriz, con densidad decreciente a medida que avanzas a índices más grandes para las filas y columnas Para volver a los índices originales en mi enfoque, simplemente cree un par de asignaciones: "original al clasificado" y "clasificado al original", y puede recrear a la perfección los datos originales, si lo desea.

0

@ La respuesta de Iterator es muy útil para mi aplicación, pero es una pena que su respuesta no incluya un ejemplo para ilustrar la idea. Aquí está mi implementación de la idea de reordenar las filas y columnas de una matriz dispersa muy grande (por ejemplo, con aproximadamente un millón de filas y unos pocos miles de columnas en el superordenador con suficiente memoria para cargar la matriz dispersa).

library(Matrix) 

sparseY <- sparseMatrix(i=sample(2000, 500, replace=TRUE), j=sample(1000,500, replace=TRUE), x=sample(10000,500)) 

# visualize the original sparse matrix 
image(sparseY, aspect=1, colorkey=TRUE, main="The original sparse matrix") 

numObs <- length([email protected]) 
# replace all non-zero entries with 1 to calculate #non-zero entries per row/column and use rank() to sort based on supports 
logicalY <- sparseY; [email protected] <- rep(1, numObs) 

# calculate the number of observed entries per row/column 
colObsFreqs <- colSums(logicalY) 
rowObsFreqs <- rowSums(logicalY) 

colObsFreqs 
rowObsFreqs 

# get the rank of supports for rows and columns 
colRanks <- rank(-1*colObsFreqs, ties="first") 
rowRanks <- rank(-1*rowObsFreqs, ties="first") 

# Sort the ranks from small to large 
sortColInds <- sort(colRanks, index.return=TRUE) 
sortRowInds <- sort(rowRanks, index.return=TRUE) 

# reorder the original sparse matrix so that the maximum density data block is placed in the upper left corner of the matrix, with decreasing density as you move to larger indices for the rows and columns. 
sparseY <- sparseY[ sortRowInds$ix, sortColInds$ix ] 

# visualize the reordered sparse matrix 
image(sparseY, aspect=1, colorkey=TRUE, main="The sparse matrix after reordering") 

logicalY <- sparseY; [email protected] <- rep(1, numObs) 
# Check whether the resulting sparse matrix is what's expected, i.e. with the maximum density data block placed in the upper left corner of the matrix 
colObsFreqs <- colSums(logicalY) 
rowObsFreqs <- rowSums(logicalY) 

colObsFreqs 
rowObsFreqs 
Cuestiones relacionadas