在不丢失 dimnames 的情况下从稀疏矩阵转换为密集矩阵?

convert from sparse Matrix to dense matrix without losing dimnames?

将稀疏 Matrix 对象(来自 Matrix 包)转换为普通的旧 base-R 密集 matrix 对象似乎丢失了 row/column 名称。

m <- matrix(0, 3,3, dimnames = list(LETTERS[1:3], LETTERS[1:3]))
dimnames(m)
## [[1]]
## [1] "A" "B" "C"
## 
## [[2]]
## [1] "A" "B" "C"

转换为 一个 Matrix 没问题:

dimnames(M <- Matrix::Matrix(m))
## [[1]]
## [1] "A" "B" "C"
## [[2]]
## [1] "A" "B" "C"

但是转换回来似乎失去了 row/column 名字:

dimnames(as.matrix(M))
## NULL
dimnames(as(M, "matrix"))
## NULL

我知道我可以通过存储 dimnames 然后将它们附加到新对象来解决这个问题(见下文),但我觉得我不应该这样做......我是否错过了 transparent/better 进行转换的方式,或者为什么 dimnames 在进行此转换时 应该保留的逻辑原因??

## workaround/hack
dn <- dimnames(m)
m2 <- as.matrix(M)
dimnames(m2) <- dn

澄清一下,我想处理 M 已经存在的情况 m 还没有 (即旧的 m[] <- 替换 m 的内容同时保持其属性不变的技巧似乎不起作用 ...)

看起来“m”和“M”的区别在于对象类型:

m <- matrix(0, 3,3, dimnames = list(LETTERS[1:3], LETTERS[1:3]))
M <- Matrix::Matrix(m)

typeof(m)
#> [1] "double"

typeof(M)
#> [1] "S4"

我不知道是否有 'easy' 方法,但另一种选择可能是:

m <- matrix(0, 3,3, dimnames = list(LETTERS[1:3], LETTERS[1:3]))
dimnames(m)
#> [[1]]
#> [1] "A" "B" "C"
#> 
#> [[2]]
#> [1] "A" "B" "C"
M <- Matrix::Matrix(m)
m <- as.matrix(M)
dimnames(m) <- M@Dimnames
m
#>   A B C
#> A 0 0 0
#> B 0 0 0
#> C 0 0 0

或者也许:

m <- matrix(M, nrow = M@Dim, dimnames = M@Dimnames)
m
#>   A B C
#> A 0 0 0
#> B 0 0 0
#> C 0 0 0

[更新 1:bug report] [更新 2:patch]

这里[dD]imnames的丢失似乎是Matrix中的一个错误,至少在"Matrix"的特定子class的实现中是这样,即"ddiMatrix"(参见 ?`ddiMatrix-class`)。

library("Matrix")
M <- Matrix(0, 3L, 3L, dimnames = list(LETTERS[1:3], LETTERS[1:3]))
M
3 x 3 diagonal matrix of class "ddiMatrix"
  A B C
A 0 . .
B . 0 .
C . . 0

有一种方法可以将 "ddiMatrix" 强制转换为 "matrix",当您执行 as(M, "matrix") 时会调用它,但它不会保留 [dD]imnames,正如您观察到的那样。

selectMethod("coerce", signature(from = "ddiMatrix", to = "matrix"))
Method Definition:

function (from, to = "matrix", strict = TRUE) 
base::diag(if (from@diag == "U") as1(from@x) else from@x, nrow = from@Dim[1])
<bytecode: 0x11e7dc068>
<environment: namespace:Matrix>

Signatures:
        from        to      
target  "ddiMatrix" "matrix"
defined "ddiMatrix" "matrix"

您可以使用从 "ddiMatrix""dgCMatrix" 的中间强制转换来解决该错误,这是一个更通用且更仔细实现的 class 稀疏数字矩阵(请参阅 ?`dgCMatrix-class`).从 "ddiMatrix""dgCMatrix""matrix" do 的强制保留 [dD]imnames:

MM <- as(M, "dgCMatrix")
MM
3 x 3 sparse Matrix of class "dgCMatrix"
  A B C
A . . .
B . . .
C . . .
m <- as(MM, "matrix")
m
  A B C
A 0 0 0
B 0 0 0
C 0 0 0

或简单地 m <- as(as(M, "dgCMatrix"), "matrix").

需要说明的是,您的方法更快 并且 更透明。我介绍这个主要是为了揭露这个错误影响 "ddiMatrix" 但不是 Matrix 中实现的稀疏数字矩阵的所有 classes 的事实。如果您的用例实际上不需要 "ddiMatrix",那么您不必担心自己会保留 [dD]imnames

FWIW,在与 Matrix 强制转换作斗争时,我发现它有助于:

  1. 使用showClass("Matrix")提醒自己"Matrix"子classes的继承结构。
  2. 请参阅 ?`<classname>-class` 以了解 (1) 中报告的 classes 及其位置的人类可读描述。
  3. 使用 selectMethod("coerce", signature(from=, to=)) 找到 as 实际调用的方法(尽管,由于强制转换通常在 C 中实现,selectMethod 结果除了告诉我要做什么之外可能没有帮助在 Matrix/src).
  4. 中搜索