分享免费的编程资源和教程

网站首页 > 技术教程 正文

使用 Python 进行矩阵分解 [;1] python矩阵

goqiw 2024-10-16 11:25:31 技术教程 21 ℃ 0 评论

器学习和数值编程中的基本算法之一是矩阵分解。这个想法是将源矩阵 M 分解为两个矩阵 A 和 B,使 A * B = M。矩阵分解没有任何直接用途,但分解是矩阵求逆和其他几个基本算法的关键组成部分。

在我居住的太平洋西北部的一个下雨周末(是的,PNW 中的“下雨”是多余的)我决定使用 Python 实现一个矩阵分解函数。有几种分解算法。我使用了克劳特的算法。

我的演示程序从矩阵 M 开始:

[3.0 7.0 2.0 5.0]  
[1.0 8.0 4.0 2.0]  
[2.0 1.0 9.0 3.0]  
[5.0 4.0 7.0 1.0] ])

得到的 LUM(“下-上”)分解和辅助排列数组是:

[ 5.0000   4.0000   7.0000   1.0000 ]
[ 0.2000   7.2000   2.6000   1.8000 ]
[ 0.4000  -0.0833   6.4167   2.7500 ]
[ 0.6000   0.6389  -0.6017   4.9048 ]

[ 3  1  2  0 ]

LUM 的下半部分(对角线下方的元素,对角线上有虚拟 1s)是分解的第一部分:

[ 1.0000   0.0000   0.0000   0.0000 ]
[ 0.2000   1.0000   0.0000   0.0000 ]
[ 0.4000  -0.0833   1.0000   0.0000 ]
[ 0.6000   0.6389  -0.6017   1.0000 ]

LUM的上半部分是:

[ 5.0000   4.0000   7.0000   1.0000 ]
[ 0.0000   7.2000   2.6000   1.8000 ]
[ 0.0000   0.0000   6.4167   2.7500 ]
[ 0.0000   0.0000   0.0000   4.9048 ]

当您将低乘以高时,结果几乎是原来的 M,除了一些行被置换:

[ 5.0000   4.0000   7.0000   1.0000 ]
[ 1.0000   8.0000   4.0000   2.0000 ]
[ 2.0000   1.0000   9.0000   3.0000 ]
[ 3.0000   7.0000   2.0000   5.0000 ]

要恢复原始矩阵,您可以根据排列数组 [3 1 2 0] 中的信息重新排列行。

当我实现 Crout 的分解时,我在交换矩阵的两行时遇到了一个令人讨厌的语法问题。我花了一个小时调试。详细信息可能会填满整篇博客文章,因此我只需要注意交换矩阵的两行需要小心。

艺术中的分解。左图:艺术家 Cane Dojcilovic。中心:由艺术家阿尔贝托·塞维索 (Alberto Seveso) 创作。右图:艺术家 Antonio Saraiva。

演示代码。用正确的符号替换“lt”(小于)、“gt”等。

# crout.py 
# crout 的分解

将numpy导入为np

def  mat_decompose (m) : 
  # 矩阵行列式和逆矩阵的 Crout LU 分解
  # 在 lum[][] 中存储组合的下和上
  # 将行排列存储到 perm[] 
  # 切换是 +1(偶数)或 -1 行排列数
  #lower在对角线上获得虚拟的1.0s(0.0s以上)#upper在对角线
  上获得lum值(0.0s以下)

  切换 = + 1   # 偶数
  n = len(m)
  lum = np.copy(m)
  perm = np.arange(n)

  for j in range( 0 ,n -1 ):   # 按列处理。注意 n-1 
    max = np.abs(lum[j][j])   # 或 lum[i,j]
    piv = j

    对于我在范围第(j + 1,n)的:
      xij = np.abs(lum[i][j])
      如果xij "gt"最大值:
        最大值 = xij; piv = 我

    if piv != j:   # 交换行 j, piv 
      lum[[j,piv]] = lum[[piv,j]]   # 特殊语法

      t = perm[piv]   # 交换物品
      烫[piv] = 烫[j]
      烫发[j] = t

      切换 = -切换

    xjj = lum[j][j]
    if np.abs(xjj) "gt"  1.0e-5 :   # if xjj != 0.0 
      for i in range(j+ 1 ,n):
        xij = lum[i][j] / xjj
        lum[i][j] = xij
        用于?在范围第(j + 1,n)的:
          lum[i][k] -= xij * lum[j][k]

  返回(切换,lum,烫发)

def  get_lower (lum) :
  n = len(lum)
  结果 = np.zeros((n,n))
  for i in range(n):
     for j in range(n):
       if i == j:
        结果[i][j] = 1.0 
      elif i "gt" j:
        结果[i][j] = lum[i][j]
  返回结果

def  get_upper (lum) :
  n = len(lum)
  结果 = np.zeros((n,n))
  for i in range(n):
     for j in range(n):
       if i "lte" j:
        结果[i][j] = lum[i][j]
  返回结果

def 放松(lu, perm) :
  结果 = np.copy(lu)
  对于我在范围(LEN(烫发)):
    j = 烫发[i]
    结果[i] = lu[j]
  返回结果
    

def  main () : 
  print( "\n开始Crout的矩阵分解演示" )
  np.set_printoptions(formatter={ 'float' : '{: 0.4f}' .format})
 
  m = np.array([[ 3.0 , 7.0 , 2.0 , 5.0 ],
                [ 1.0 , 8.0 , 4.0 , 2.0 ],
                [ 2.0 , 1.0 , 9.0 , 3.0 ],
                [ 5.0 , 4.0 , 7.0 , 1.0 ]])

  打印(“\纳米=”)
  打印(米)

  (toggle, lum, perm) = mat_decompose(m)

  打印(“\nlum =”)
  打印(流明)
  打印(“\nperm =”)
  打印(烫发)
  
  下 = get_lower(lum)
  打印(“\n较低=”)
  打印(下)

  上 = get_upper(lum)
  打印(“\nupper =”)
  打印(上)

  lu = np.matmul(下,上)
  打印(“\n下*上=“)
  打印(卢)

  原始 = 放松(lu,烫发)
  打印(“\n原始=”)
  打印(原件)

  打印(“\n结束演示”)

如果__name__ == "__main__":
  主要的()

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表