如何将稀疏矩阵转换为密集矩阵而不丢失维度名称?

4
将来自Matrix包的稀疏Matrix对象转换为传统的基础R密集矩阵对象似乎会丢失行/列名称。
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"

转换为矩阵很容易:

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

但是转换回去似乎会丢失行/列名称:

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

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

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

为了澄清,我想处理这样一种情况:已经定义了M,但是m没有(即旧的m[] <-替换m的内容,同时保留其属性的技巧似乎不起作用...)


2
错误已经修复,在Matrix r3418中。下一个版本应该包含这个补丁。 - Mikael Jagan
谢谢你,Mikael(特别是报告方面)。Matrix 1.4-0确实于昨天发布到CRAN。 - Martin Mächler
2个回答

2

[更新 1: 错误报告] [更新 2: 补丁]

这里丢失了 [dD]imnames,看起来是 Matrix 的一个 bug,至少在特定的 "Matrix" 子类实现中出现了问题,即 "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

当你执行as(M, "matrix")时,有一种从"ddiMatrix""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"来解决该bug,后者是一种更通用、更精心实现的稀疏数值矩阵类(请参见?`dgCMatrix-class`)。从"ddiMatrix""dgCMatrix"再到"matrix"的强制转换确实保留了[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中实现的稀疏数值矩阵类。如果您的用例实际上并不需要"ddiMatrix",那么您不必担心自己保留[dD]imnames

顺便说一下,在处理Matrix强制转换时,我发现以下方法很有用:

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

1

看起来“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"

我不知道是否有“简单”的方法,但另一种选择可能是:
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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接