首页 > 解决方案 > 对于来自 {Matrix} 的稀疏矩阵,是否有带有 R 函数 duplicated() 的方法?

问题描述

有没有一种简单的方法来编写duplicated上课的方法dgCMatrix?这是一个小例子,所需的输出是which(duplicated(as.matrix(A), MARGIN = 2)).

# assign example
library(Matrix)
i <- c(1,     3:7, 2, 1, 2, 3)
j <- c(2,  1, 3:6, 1, 7, 8, 8)
x <- c(1:7, 1, 7, 2)
(A <- sparseMatrix(i, j, x = x))
#R 7 x 8 sparse Matrix of class "dgCMatrix"
#R 
#R [1,] . 1 . . . . 1 .
#R [2,] 7 . . . . . . 7
#R [3,] 2 . . . . . . 2
#R [4,] . . 3 . . . . .
#R [5,] . . . 4 . . . .
#R [6,] . . . . 5 . . .
#R [7,] . . . . . 6 . .

# column 7 and 8 match with 1 and 2
which(duplicated(as.matrix(A), MARGIN = 2))
#R [1] 7 8

duplicated(A)
#R Error in duplicated.default(A) : duplicated() applies only to vectors

我使用的矩阵相当大,所以我想避免将矩阵转换为密集矩阵。出于同样的原因,该功能也应该很快。

到目前为止,我最好的选择是查看代码duplicated,也许可以用Rccp.

标签: rmatrixsparse-matrix

解决方案


我的想法是将这个稀疏矩阵恢复到一个列表中,RowLst或者ColLst,这样Rowlst[[i]]或者ColLst[[i]]是第 i 行或第 i 列的压缩向量。然后申请duplicated这个名单。

duplicated.dgCMatrix <- function (dgCMat, MARGIN, include.all.zero.vectors = TRUE) {
  MARGIN <- as.integer(MARGIN)
  J <- rep(1:ncol(dgCMat), diff(dgCMat@p))
  I <- dgCMat@i + 1
  x <- dgCMat@x
  if (MARGIN == 1L) {
    ## check duplicated rows
    names(x) <- J
    if (include.all.zero.vectors) {
      RowLst <- split(x, factor(I, levels = 1:nrow(dgCMat)))
      } else {
      RowLst <- split(x, I)  ## will do `factor(I)` internally in `split`
      }
    result <- duplicated.default(RowLst)
    } else if (MARGIN == 2L) {
    ## check duplicated columns
    names(x) <- I
    if (include.all.zero.vectors) {
      ColLst <- split(x, factor(J, levels = 1:ncol(dgCMat)))
      } else {
      ColLst <- split(x, J)  ## will do `factor(J)` internally in `split`
      }
    result <- duplicated.default(ColLst)
    } else {
    warning("invalid MARGIN; return NULL")
    result <- NULL
    }
  result
  }

which(duplicated.dgCMatrix(A, 2))
#[1] 7 8

20650和我的讨论揭示了一些值得评论的东西。

  1. 没想到通过上面的自定义函数,S3 方法调度对 S4 对象有效。所以,which(duplicated(A, 2))够了。
  2. duplicated.matrix(t(A))duplicated.array(A, MARGIN = 2)在这里返回正确的结果。起初我们以为我们找到了一个隐藏的宝藏,但通过检查它们的来源,我们发现它们都依赖于apply,这将对as.matrix二维输入对象进行运算。

OP 在他的申请中占有一席之地。原始解决方案没有考虑全零行/列。添加参数的新版本include.all.zero.vectors解决了这个问题。基本上,我们控制用于 的因子级别split,以便NULL在列表中为全零的行/列分配一个条目,而不是被忽略。


推荐阅读