使用包含行名和列名的索引向量将值添加到矩阵

时间:2011-08-23 16:37:01

标签: r matrix sparse-matrix indices

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

创建稀疏矩阵
sparseMatrix(i=df$row,j=df$column,x=df$value)

但是,由于我的值,我最终得到了一个稀疏矩阵,该矩阵有数百万行数万列(其中大多数是空的,因为我的子集排除了大多数行和列)。所有这些零行和列最终都会使我的一些函数倾斜(例如,采用聚类 - 当一个原点甚至不是有效点时,我最终得到一个包含原点的聚类)。 我想执行相同的操作,但使用i和j作为rownames和colnames。我已经尝试创建一个密集的矢量,采样到最大尺寸并使用

添加值
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

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

> 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 个答案:

答案 0 :(得分:4)

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

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

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

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

> 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

答案 1 :(得分: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

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

答案 2 :(得分:1)

您的第一个问题源于coordinate list (COO)具有行和列索引的非连续值的事实。面对这种情况,或者甚至在处理大多数稀疏矩阵时,我倾向于通过支持对行和列进行重新排序。

您可以通过两种方式执行此操作:

  1. 生成稀疏矩阵以及colSums的{​​{1}}和rowSums以获取支持值,或
  2. 使用logical(yourMatrix)table(来自bigtabulate套件)等函数计算坐标列表中每个值的唯一时间数。 (我的偏好是bigmemory。)
  3. 获得支持后,您可以使用bigtabulate函数(实际上是rank)根据排名将原始索引映射到新索引。

    此时,如果使用rank(-1 * support, ties = "first")创建矩阵,它将只生成一个矩阵,其尺寸使得所有行和列都具有支持。它不会映射到更大的东西。

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

答案 3 :(得分: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
相关问题