是否存在一种针对{Matrix}中的稀疏矩阵的R函数plicated()方法?

时间:2018-07-21 14:51:16

标签: r matrix sparse-matrix

是否有一种简便的方法来编写duplicated的{​​{1}}类的方法?这是一个小例子,所需的输出是 dgCMatrix

which(duplicated(as.matrix(A), MARGIN = 2))

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

到目前为止,我最好的选择是看the code for duplicated并用# 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 写一个等效函数。

2 个答案:

答案 0 :(得分:3)

我的想法是将这个稀疏矩阵还原到列表RowLstColLst中,使得Rowlst[[i]]ColLst[[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条目,而不是被忽略。

答案 1 :(得分:1)

李哲源's solution在纯零列的情况下效果很好。例如,

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

which(duplicated(as.matrix(A), MARGIN = 2))
#R [1] 2 5 6
which(duplicated.dgCMatrix(A, 2))
#R [1] 2 4

尽管稍作修改即可解决此问题

duplicated.dgCMatrix <- function (dgCMat, MARGIN) {
  MARGIN <- as.integer(MARGIN)
  n <- nrow(dgCMat)
  p <- ncol(dgCMat)
  J <- rep(1:p, diff(dgCMat@p))
  I <- dgCMat@i + 1
  x <- dgCMat@x
  if (MARGIN == 1L) {
    ## check duplicated rows
    names(x) <- J
    RowLst <- split(x, I)
    is_empty <- setdiff(1:n, I)
    result <- duplicated.default(RowLst)
  } else if (MARGIN == 2L) {
    ## check duplicated columns
    names(x) <- I
    ColLst <- split(x, J)
    is_empty <- setdiff(1:p, J)
    result <- duplicated.default(ColLst)
  } else {
    warning("invalid MARGIN; return NULL")
    result <- NULL
  }

  if(any(is_empty)){
    out <- logical(if(MARGIN == 1L) n else p)
    out[-is_empty] <- result
    if(length(is_empty) > 1)
      out[is_empty[-1]] <- TRUE
    result <- out
  }

  result
}

之后我们得到

which(duplicated.dgCMatrix(A, 2))
#R [1] 2 5 6

# check that it works with the transpose
which(duplicated.dgCMatrix(t(A), 1))
#R [1] 2 5 6