【问题标题】:Solving non-square linear system with R用 R 求解非平方线性系统
【发布时间】:2013-11-14 20:01:08
【问题描述】:

如何用 R 求解非平方线性系统:A X = B

(在系统无解或有无穷多个解的情况下)

例子:

A=matrix(c(0,1,-2,3,5,-3,1,-2,5,-2,-1,1),3,4,T)
B=matrix(c(-17,28,11),3,1,T)

A
     [,1] [,2] [,3] [,4]
[1,]    0    1   -2    3
[2,]    5   -3    1   -2
[3,]    5   -2   -1    1


B
     [,1]
[1,]  -17
[2,]   28
[3,]   11

【问题讨论】:

  • 请查看link。一个好的可重复示例将帮助其他人更轻松地解决您的问题。
  • 我添加了一个可重现的例子。
  • solve 的文档文件中,他们提到“qr.solve 可以处理非正方形系统”。因此,当我使用此处给出的 A 和 B 并尝试 qr.solve(A,B) 时,我收到错误消息 Error in qr.solve(A, B) : singular matrix 'a' in solve。有什么想法吗?

标签: r math system linear-algebra numerical-computing


【解决方案1】:

如果矩阵 A 的行数多于列数,则应使用最小二乘拟合。

如果矩阵 A 的行数少于列数,则应执行奇异值分解。每个算法都尽其所能通过假设为您提供解决方案。

这是一个链接,展示了如何使用 SVD 作为求解器:

http://www.ecse.rpi.edu/~qji/CV/svd_review.pdf

让我们把它应用到你的问题上,看看它是否有效:

你的输入矩阵A和已知的RHS向量B

> A=matrix(c(0,1,-2,3,5,-3,1,-2,5,-2,-1,1),3,4,T)
> B=matrix(c(-17,28,11),3,1,T)
> A
     [,1] [,2] [,3] [,4]
[1,]    0    1   -2    3
[2,]    5   -3    1   -2
[3,]    5   -2   -1    1
> B
     [,1]
[1,]  -17
[2,]   28
[3,]   11

让我们分解你的A 矩阵:

> asvd = svd(A)
> asvd
$d
[1] 8.007081e+00 4.459446e+00 4.022656e-16

$u
           [,1]       [,2]       [,3]
[1,] -0.1295469 -0.8061540  0.5773503
[2,]  0.7629233  0.2908861  0.5773503
[3,]  0.6333764 -0.5152679 -0.5773503

$v
            [,1]       [,2]       [,3]
[1,]  0.87191556 -0.2515803 -0.1764323
[2,] -0.46022634 -0.1453716 -0.4694190
[3,]  0.04853711  0.5423235  0.6394484
[4,] -0.15999723 -0.7883272  0.5827720

> adiag = diag(1/asvd$d)
> adiag
          [,1]      [,2]        [,3]
[1,] 0.1248895 0.0000000 0.00000e+00
[2,] 0.0000000 0.2242431 0.00000e+00
[3,] 0.0000000 0.0000000 2.48592e+15

这是关键:d 中的第三个特征值非常小;相反,adiag 中的对角元素非常大。在求解之前,将其设置为零:

> adiag[3,3] = 0
> adiag
          [,1]      [,2] [,3]
[1,] 0.1248895 0.0000000    0
[2,] 0.0000000 0.2242431    0
[3,] 0.0000000 0.0000000    0

现在让我们计算解决方案(请参阅上面我给你的链接中的幻灯片 16):

> solution = asvd$v %*% adiag %*% t(asvd$u) %*% B
> solution
          [,1]
[1,]  2.411765
[2,] -2.282353
[3,]  2.152941
[4,] -3.470588

现在我们有了一个解决方案,让我们将其替换回去,看看它是否给了我们相同的B

> check = A %*% solution
> check
     [,1]
[1,]  -17
[2,]   28
[3,]   11

那是你开始的 B 方面,所以我认为我们很好。

这是来自 AMS 的另一个很好的 SVD 讨论:

http://www.ams.org/samplings/feature-column/fcarc-svd

【讨论】:

  • 既然我已经给了你相关的名字,也许你可以做一些研究,然后自己先尝试一下。
  • 我做过 - 最小二乘法和 SVD。查看 R 中的 lm() 和 svd() 方法。
  • 我已将 SVD 解决方案添加到我的答案中。
  • 我认为这是因为线性求解器函数对非方阵毫无意义。就像我在原始答案中所说的那样,如果 m > n 你有最小二乘;如果 m
  • 你正在构建的矩阵 asvd$v %*% adiag %*% t(asvd$u) 是 A 的伪逆矩阵,不是吗?
【解决方案2】:

目的是解决Ax = b

其中Aqpxq的1 和 bp by 1 对于 x 给定 Ab

方法 1:广义逆:Moore-Penrose https://en.wikipedia.org/wiki/Generalized_inverse

等式两边相乘,我们得到

A'Ax = A' b

其中 A'A 的转置。注意 A'A 现在是 q by q 矩阵。现在解决这个问题的一种方法是将等式两边乘以 A'A 的倒数。这给了,

x = (A'A)^{-1} A' b

这是广义逆背后的理论。这里 G = (A'A)^{-1} A'A 的伪逆。

library(MASS)

ginv(A) %*% B

#          [,1]
#[1,]  2.411765
#[2,] -2.282353
#[3,]  2.152941
#[4,] -3.470588

方法 2:使用 SVD 的广义逆。

@duffymo 使用 SVD 获得 A 的伪逆。

但是,svd(A)$d 的最后一个元素可能没有本示例中的那么小。因此,可能不应按原样使用该方法。这是一个示例,其中 A 的最后一个元素都不接近于零。

A <- as.matrix(iris[11:13, -5])    
A
#   Sepal.Length Sepal.Width Petal.Length Petal.Width
# 11          5.4         3.7          1.5         0.2
# 12          4.8         3.4          1.6         0.2
# 13          4.8         3.0          1.4         0.1

svd(A)$d
# [1] 10.7820526  0.2630862  0.1677126

一种选择是看成cor(A)中的奇异值

svd(cor(A))$d
# [1] 2.904194e+00 1.095806e+00 1.876146e-16 1.155796e-17

现在,很明显只有两个大奇异值存在。因此,现在可以在 A 上应用 svd 以获得伪逆,如下所示。

svda <- svd(A)
G = svda$v[, 1:2] %*% diag(1/svda$d[1:2]) %*% t(svda$u[, 1:2])
# to get x
G %*% B

【讨论】:

  • 在 CRAN 中可用。
  • 我相信您的方法 1 与您的方法 2 相同,因为 MASS::ginv(以及 pracma::pinv),使用与方法 2 完全相同的代码来计算 Moore-Penrose 伪逆(即通过SVD)
  • 这是真的,因为我使用了MASS::ginv 来演示该方法。有时我会用不同的实现来编辑答案。干杯。
猜你喜欢
  • 2019-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-13
  • 2019-06-07
  • 2019-10-05
相关资源
最近更新 更多