6

假设我有一个非常大的稀疏数据矩阵,但我只对查看它的样本感兴趣,使其更加稀疏。假设我还有一个三元组数据框,包括数据的行/列/值的列(从 csv 文件导入)。我知道我可以使用 library(Matrix) 的 sparseMatrix() 函数来创建一个稀疏矩阵

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

但是,由于我的值,我最终得到了一个稀疏矩阵,它是数百万行乘数万列(其中大部分是空的,因为我的子集不包括大部分行和列)。所有这些零行和列最终都会扭曲我的一些函数(以集群为例——当原点甚至不是有效点时,我最终得到一个包含原点的集群)。我想执行相同的操作,但使用 i 和 j 作为行名和列名。我尝试创建一个密集向量,采样到最大大小并使用添加值

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

(实际上我一直将它设置为 1,因为我对这种情况下的值不感兴趣)但我发现它填充了整个矩阵,因为它需要所有行和列的交叉,而不仅仅是row1*col1, row2*col2... 有人知道一种方法来完成我想要做的事情吗?或者,我可以填充稀疏矩阵并简单地让它以某种方式丢弃所有零行和列以将自身压缩成更密集的形式(但我想保留一些对原始行号和列号的引用)我很感激任何建议!

这是一个例子:

> 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

我想去掉第 1,3 和 5 列以及第 2 和第 4 行。这是一个非常简单的例子,但想象一下,如果不是第 1、3 和 5 行,它们是 1000、3000 和 5000。然后它们之间会有更多的空行。这是当我使用具有命名行/列的密集矩阵时发生的情况

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

4 回答 4

4

您的代码几乎可以工作,您只需要将cbind行名和列名放在一起。然后将结果矩阵的每一行视为一对,而不是分别处理行和列。

> 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

如果您使用因子,这可能会更快。

> 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

您还可以在调用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

请注意,其他解决方案之一可能更快;如果有大量数据,转换为因子可能会很慢。

于 2011-08-23T18:04:47.233 回答
4

当您说“摆脱”某些列/行时,您的意思是这样的:

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

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

子集工作,所以你只需要找出哪些行和列是空的?如果这是正确的,那么您可以使用Matrix包对这些进行了增强,colSums()以便为稀疏矩阵提供适当的方法。这应该在操作期间保持稀疏性rowSums()

> 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

或者,也许更安全

> 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
于 2011-08-23T17:49:45.717 回答
1

您的第一个问题源于坐标列表 (COO)的行索引和列索引的值不连续。面对这种情况,或者甚至在处理大多数稀疏矩阵时,我倾向于通过它们的支持来重新排序行和列。

您可以通过两种方式做到这一点:

  1. 生成稀疏矩阵和 docolSumsrowSumsoflogical(yourMatrix)以获得支持值,或者
  2. 使用类似tableor的函数bigtabulate(来自bigmemory套件)来计算每个值在坐标列表中出现的唯一次数。(我的偏好是bigtabulate。)

获得支持后,您可以使用rank函数(实际上是rank(-1 * support, ties = "first"))根据它们的等级将原始索引映射到新索引。

此时,如果您使用 来创建矩阵sparseMatrix,它只会生成一个具有维度的矩阵,使得您的所有行和列都有支持。它不会映射到更大的东西。

这类似于@GavinSimpson 的方法,尽管他的方法只删除丢失的行和列,而我的方法重新排序以将最大密度放在矩阵的左上角,随着您移动到更大的行索引而降低密度和列。为了在我的方法中映射回原始索引,只需创建一对映射:“原始到排名”和“排名到原始”,如果您愿意,您可以完美地重新创建原始数据。

于 2011-08-23T19:55:52.193 回答
0

@Iterator 的回答对我的申请非常有帮助,但很遗憾他/她的回答没有包含一个例子来说明这个想法。这是我对非常大的稀疏矩阵的行和列重新排序的想法的实现(例如,在超级计算机上有大约一百万行和几千列,有足够的内存来加载稀疏矩阵)。

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( sparseY@x )
# 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; logicalY@x <- 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; logicalY@x <- 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
于 2017-02-02T12:47:27.750 回答