2

A我在 R 中有以下矩阵:

           # [,1]       [,2]   [,3]       [,4]
# [1,] -1.1527778  0.4444444  0.375  0.3333333
# [2,]  0.5555556 -1.4888889  0.600  0.3333333
# [3,]  0.6250000  0.4000000 -1.825  0.8000000
# [4,]  0.6666667  0.6666667  0.200 -1.5333333

A <- structure(c(-1.15277777777778, 0.555555555555556, 0.625, 0.666666666666667, 
0.444444444444444, -1.48888888888889, 0.4, 0.666666666666667, 
0.375, 0.6, -1.825, 0.2, 0.333333333333333, 0.333333333333333, 
0.8, -1.53333333333333), .Dim = c(4L, 4L), .Dimnames = list(NULL, 
    NULL))

我计算它的LU分解如下:

library(Matrix)
ex <- expand(lu(t(A)))
L <- ex$L
P <- ex$P
C <- U <- ex$U
C[lower.tri(U)] <- L[lower.tri(L)]

print(C)

# 4 x 4 Matrix of class "dgeMatrix"
           # [,1]       [,2]       [,3]          [,4]
# [1,] -1.1527778  0.5555556  0.6250000  6.666667e-01
# [2,] -0.3855422 -1.2746988  0.6409639  9.236948e-01
# [3,] -0.3253012 -0.6124764 -1.2291115  9.826087e-01
# [4,] -0.2891566 -0.3875236 -1.0000000 -2.220446e-16

另一方面,这是同一工作的 Python 代码:

lu, piv = scipy.linalg.lu_factor(A.T, check_finite=False)

print(lu)

# [[ -1.15277778e+00   5.55555556e-01   6.25000000e-01   6.66666667e-01]
 # [ -3.85542169e-01  -1.27469880e+00   6.40963855e-01   9.23694779e-01]
 # [ -2.89156627e-01  -3.87523629e-01   1.22911153e+00  -9.82608696e-01]
 # [ -3.25301205e-01  -6.12476371e-01  -1.00000000e+00   7.69432827e-16]]

我想知道为什么 R 和 Python 中的两个Clu矩阵(分别)不一样。关键是我必须得到与 Python 版本(即矩阵lu)相同的结果。你知道我做错了什么吗?

4

1 回答 1

7

1.5年后才意识到我原来的答案并不完全正确,这很尴尬。虽然它正确地指出问题中的排名不足A是原因,但将其归结为根本原因是不正确的。真正的问题是枢轴的非唯一选择,即使A是全等级也可能发生(尽管可能性较小)。鉴于这篇文章已经被浏览了 700 多次并且获得了 6 分,我可能误导了很多读者。对不起!

我发布了编写一个可跟踪的 R 函数,该函数模仿 LAPACK 的 dgetrf 进行 LU 分解并刚刚回答了它。该问题包含一个LU没有旋转的 LU 分解函数,答案包含两个函数LUP和一个与 LAPACK 的dgetrfLUP2一致的具有行旋转的版本,它是密集方法和 R 基函数的基础。特别是,该函数允许跟踪逐步分解。我将在这里使用此功能进行调查。Matrix::lusolve.LUP2


所以你正在分解 的转置A

从 R 和 Python 的输出中,我们看到它们产生相同的 1st pivot-1.1527778和 2nd pivot -1.2746988,而 3rd pivot 不同。因此,当分解完成前两列/行并进行到第三列/行时,肯定会发生一些有趣的事情。让我们在这一点上暂停 R 的 LU 分解:

oo <- LUP2(t(A), to = 2)
#           [,1]       [,2]       [,3]       [,4]
#[1,] -1.1527778  0.5555556  0.6250000  0.6666667
#[2,] -0.3855422 -1.2746988  0.6409639  0.9236948
#[3,] -0.3253012 -0.6124764 -1.2291115  0.9826087
#[4,] -0.2891566 -0.3875236  1.2291115 -0.9826087
#attr(,"to")
#[1] 2
#attr(,"pivot")
#[1] 1 2 3 4

至此,高斯消元t(A)化为

getU(oo)
#           [,1]       [,2]       [,3]       [,4]
#[1,] -1.1527778  0.5555556  0.6250000  0.6666667
#[2,]  0.0000000 -1.2746988  0.6409639  0.9236948
#[3,]  0.0000000  0.0000000 -1.2291115  0.9826087
#[4,]  0.0000000  0.0000000  1.2291115 -0.9826087
#attr(,"to")
#[1] 2

哇,我们现在看到了一些非常有趣的东西:第 3 行和第 4 行只是符号变化不同。那么高斯消元法不是唯一的,因为它们具有相同的绝对值,-1.2291115或者可以是枢轴。1.2291115

显然,R 选择-1.2291115了作为支点,但 Python 选择1.2291115了作为支点。在 Python 中将发生第 3 行和第 4 行之间的行交换。在你的问题中,你没有报告 Python 给你的排列索引,但它应该1, 2, 4, 3,而不是1, 2, 3, 4R 中的。


无论哪种方式,该U因子最终都会在底部出现一行零,因此t(A)orA不是满秩。如果您想看到两个软件之间的行为更加一致,您最好尝试使用全秩矩阵。在这种情况下,在 LU 分解期间,您不太可能有多个枢轴选择。您可以通过以下方式在 R 中生成随机全秩矩阵

A <- matrix(runif(16), 4, 4)
于 2017-01-10T14:27:09.137 回答