【问题标题】:Creating a symmetric matrix in R在 R 中创建对称矩阵
【发布时间】:2013-08-10 18:54:12
【问题描述】:

我在 R 中有一个应该是对称的矩阵,但是,由于机器精度,该矩阵永远不是对称的(值相差大约 10^-16)。因为我知道矩阵是对称的,所以到目前为止我一直在这样做以解决这个问题:

s.diag = diag(s)
s[lower.tri(s,diag=T)] = 0
s = s + t(s) + diag(s.diag,S)

有更好的单行命令吗?

【问题讨论】:

    标签: r symmetric


    【解决方案1】:
    s<-matrix(1:25,5)
    s[lower.tri(s)] = t(s)[lower.tri(s)]
    

    【讨论】:

    • 非常好!当矩阵不包含数字但包含符号时​​,这也将起作用。考虑类似 s
    【解决方案2】:

    您可以使用 R 中 Matrix 包中的 forceSymmetric 函数强制矩阵对称:

    library(Matrix)
    x<-Matrix(rnorm(9), 3)
    > x
    3 x 3 Matrix of class "dgeMatrix"
               [,1]       [,2]       [,3]
    [1,] -1.3484514 -0.4460452 -0.2828216
    [2,]  0.7076883 -1.0411563  0.4324291
    [3,] -0.4108909 -0.3292247 -0.3076071
    
    A <- forceSymmetric(x)
    > A
    3 x 3 Matrix of class "dsyMatrix"
               [,1]       [,2]       [,3]
    [1,] -1.3484514 -0.4460452 -0.2828216
    [2,] -0.4460452 -1.0411563  0.4324291
    [3,] -0.2828216  0.4324291 -0.3076071
    

    【讨论】:

      【解决方案3】:

      如果值仅相差这么多,解决方法真的有必要吗?

      有人指出我之前的回答是错误的。我更喜欢其他一些,但由于我无法删除这个(已离开的用户接受),这是使用micEcon 包的另一种解决方案:

      symMatrix(s[upper.tri(s, TRUE)], nrow=nrow(s), byrow=TRUE)
      

      【讨论】:

      • 这不起作用。 ` > s=matrix(c(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16), nrow=4) > s[row( s) > col(s)] s [,1] [,2] [,3] [,4] [1,] 1 5 9 13 [2 ,] 5 6 10 14 [3,] 9 13 11 15 [4,] 10 14 15 16 `
      【解决方案4】:
       s<-matrix(1:25,5)
       pmean <- function(x,y) (x+y)/2
       s[] <- pmean(s, matrix(s, nrow(s), byrow=TRUE))
       s
      #-------
           [,1] [,2] [,3] [,4] [,5]
      [1,]    1    4    7   10   13
      [2,]    4    7   10   13   16
      [3,]    7   10   13   16   19
      [4,]   10   13   16   19   22
      [5,]   13   16   19   22   25
      

      【讨论】:

      • 或只是s &lt;- 0.5 * (s + t(s))。我更喜欢你的方法,因为取平均值是假设每个三角形边都同样正确(或错误)。而其他解决方案则随意挑选。
      【解决方案5】:

      我很想比较所有方法,所以快速运行microbenchmark。显然,最简单的0.5 * (S + t(S)) 是最快的。

      特定函数Matrix::forceSymmetric() 有时会稍微快一些,但它返回一个不同类的对象(dsyMatrix 而不是matrix),并且转换回matrix 需要很长时间(尽管可能认为将输出保持为dsyMatrix 以进一步提高计算效率是个好主意。

      S <-matrix(1:50^2,50)
      pick_lower <- function(M) M[lower.tri(M)] = t(M)[lower.tri(M)]
      
      microbenchmark::microbenchmark(micEcon=miscTools::symMatrix(S[upper.tri(S, TRUE)], nrow=nrow(S), byrow=TRUE),
                                     Matri_raw =Matrix::forceSymmetric(S),
                                     Matri_conv =as.matrix(Matrix::forceSymmetric(S)),
                                     pick_lower = pick_lower(S),
                                     base =0.5 * (S + t(S)),
                                     times=100) 
      #> Unit: microseconds
      #>        expr    min      lq       mean   median       uq        max neval cld
      #>     micEcon 62.133 74.7515  136.49538 104.2430 115.6950   3581.001   100   a
      #>   Matri_raw 14.766 17.9130   24.15157  24.5060  26.6050     63.939   100   a
      #>  Matri_conv 46.767 59.8165 5621.96140  66.3785  73.5380 555393.346   100   a
      #>  pick_lower 27.907 30.7930  235.65058  48.9760  53.0425  12484.779   100   a
      #>        base 10.771 12.4535   16.97627  17.1190  18.3175     47.623   100   a
      

      reprex package (v1.0.0) 于 2021-02-08 创建

      【讨论】:

        【解决方案6】:

        灵感来自 user3318600

            s<-matrix(1:25,5)
            s[lower.tri(s)]<-s[upper.tri(s)]
        

        【讨论】:

        • 据我所知这实际上不起作用(查看结果,或尝试isSymmetric()。您需要转置一些内容以获取替换元素正确的顺序...
        猜你喜欢
        • 1970-01-01
        • 2017-10-25
        • 1970-01-01
        • 1970-01-01
        • 2014-06-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-22
        相关资源
        最近更新 更多