python内置函数做矩阵约简

问题描述 投票:0回答:7

python有内置函数可以将矩阵转换为行阶梯形(也称为上三角)吗?

python matrix scipy
7个回答
45
投票

如果你可以使用

sympy
Matrix.rref()
可以做到:

In [8]: sympy.Matrix(np.random.random((4,4))).rref()
Out[8]: 
([1, 1.42711055402454e-17, 0, -1.38777878078145e-17]
[0,                  1.0, 0,  2.22044604925031e-16]
[0, -2.3388341405089e-16, 1, -2.22044604925031e-16]
[0, 3.65674099486992e-17, 0,                   1.0],
 [0, 1, 2, 3])

6
投票

我同意@Mile的评论对@WinstonEwert的回答计算机没有理由不能以给定的精度执行RREF。

RREF的实现应该不会很复杂,而且matlab不知何故设法拥有这个功能,所以numpy也应该有。

我做了一个非常简单直接的实现,效率很低。但对于简单的矩阵来说它效果很好:

更新:

似乎,@JustMe 在这个

rref
实现中发现了一个错误,如果输入矩阵的第一列为零,则会出现该错误。所以这里有一个更新版本。

from numpy import *

def rref(mat,precision=0,GJ=False):
    m,n = mat.shape
    p,t = precision, 1e-1**precision
    A = around(mat.astype(float).copy(),decimals=p )
    if GJ:
        A = hstack((A,identity(n)))
    pcol = -1 #pivot colum
    for i in range(m):
        pcol += 1
        if pcol >= n : break
        #pivot index
        pid = argmax( abs(A[i:,pcol]) )
        #Row exchange
        A[i,:],A[pid+i,:] = A[pid+i,:].copy(),A[i,:].copy()
        #pivot with given precision
        while pcol < n and abs(A[i,pcol]) < t:
            pcol += 1
            if pcol >= n : break
            #pivot index
            pid = argmax( abs(A[i:,pcol]) )
            #Row exchange
            A[i,:],A[pid+i,:] = A[pid+i,:].copy(),A[i,:].copy()
        if pcol >= n : break
        pivot = float(A[i,pcol])
        for j in range(m):
            if j == i: continue
            mul = float(A[j,pcol])/pivot
            A[j,:] = around(A[j,:] - A[i,:]*mul,decimals=p)
        A[i,:] /= pivot
        A[i,:] = around(A[i,:],decimals=p)
        
    if GJ:
        return A[:,:n].copy(),A[:,n:].copy()
    else:
        return A   

这里有一些简单的测试

print("/*--------------------------------------/")
print("/             Simple TEST               /")
print("/--------------------------------------*/")
A = array([[1,2,3],[4,5,6],[-7,8,9]])
R = rref(A,precision=6)
print("A:\n",A)
print("R:\n",R)
print()
print("With GJ ")
R,E =   rref(A,precision=6,GJ=True)
print("R:\n",R)
print("E:\n",E)
print("AdotE:\n",around( dot(A,E), decimals=0))
print()
A = array([[0, 0, 1], [0, 1, 0]]) 
R = rref(A, precision=1)
print("A:\n",A)
print("R:\n",R)
print()
A = array([[1,2,2,2],[2,4,6,8],[3,6,8,10]])
R = rref(A,precision=6)
print("A:\n",A)
print("R:\n",around(R, decimals=0))
print()

print("/*--------------------------------------/")
print( "/        Not Invertable TEST            /")
print( "/--------------------------------------*/")
A = array([
    [2,2,4, 4],
    [3,1,6, 2],
    [5,3,10,6]])
R = rref(A,precision=2)
print("A:\n",A)
print("R:\n",R)
print()
print("A^{T}:\n",A.T)
R = rref(A.T,precision=10)
print("R:\n",R)
/*--------------------------------------/
/             Simple TEST               /
/--------------------------------------*/
A:
 [[ 1  2  3]
  [ 4  5  6]
  [-7  8  9]]
R:
 [[1. 0. 0.]
  [0. 1. 0.]
  [0. 0. 1.]]

With GJ 
R:
 [[1. 0. 0.]
  [0. 1. 0.]
  [0. 0. 1.]]
E:
 [[-0.071428  0.142857 -0.071429]
  [-1.857142  0.714285  0.142857]
  [ 1.595237 -0.523809 -0.071428]]
AdotE:
 [[ 1.  0.  0.]
  [ 0.  1.  0.]
  [-0.  0.  1.]]

A:
 [[0 0 1]
  [0 1 0]]
R:
 [[0. 1. 0.]
  [0. 0. 1.]]

A:
 [[ 1  2  2  2]
  [ 2  4  6  8]
  [ 3  6  8 10]]
R:
 [[ 1.  2.  0. -2.]
  [ 0.  0.  1.  2.]
  [ 0.  0.  0.  0.]]

/*--------------------------------------/
/        Not Invertable TEST            /
/--------------------------------------*/
A:
 [[ 2  2  4  4]
  [ 3  1  6  2]
  [ 5  3 10  6]]
R:
 [[ 1.  0.  2.  0.]
  [-0.  1. -0.  2.]
  [ 0.  0.  0.  0.]]

A^{T}:
 [[ 2  3  5]
  [ 2  1  3]
  [ 4  6 10]
  [ 4  2  6]]
R:
 [[ 1.  0.  1.]
  [-0.  1.  1.]
  [ 0.  0.  0.]
  [ 0.  0.  0.]]


5
投票

参见 http://mail.scipy.org/pipermail/numpy-discussion/2008-November/038705.html

基本上:不要这样做。

rref 算法在计算机上实现时会产生太多不准确性。所以你要么想用另一种方式解决问题,要么使用 @aix 建议的符号。


5
投票

是的。在

scipy.linalg
中,
lu
进行 LU 分解,这本质上会得到行梯形形式。

如果您感兴趣,还有其他因式分解,例如

qr
rq
svd
等等。

文档。


2
投票

您可以自己定义:

def rref(matrix):
    A = np.array(matrix, dtype=np.float64)

    i = 0 # row
    j = 0 # column
    while True:
        # find next nonzero column
        while all(A.T[j] == 0.0):
            j += 1
            # if reached the end, break
            if j == len(A[0]) - 1 : break
        # if a_ij == 0 find first row i_>=i with a 
        # nonzero entry in column j and swap rows i and i_
        if A[i][j] == 0:
            i_ = i
            while A[i_][j] == 0:
                i_ += 1
                # if reached the end, break
                if i_ == len(A) - 1 : break
            A[[i, i_]] = A[[i_, i]]
        # divide ith row a_ij to make it a_ij == 1
        A[i] = A[i] / A[i][j]
        # eliminate all other entries in the jth column by subtracting
        # multiples of of the ith row from the others
        for i_ in range(len(A)):
            if i_ != i:
                A[i_] = A[i_] - A[i] * A[i_][j] / A[i][j]
        # if reached the end, break
        if (i == len(A) - 1) or (j == len(A[0]) - 1): break
        # otherwise, we continue
        i += 1
        j += 1

    return A

0
投票

这是一个工作版本,它几乎只是 MATLAB rref 函数的 numpy 版本:

def rref(A, tol=1.0e-12):
    m, n = A.shape
    i, j = 0, 0
    jb = []

    while i < m and j < n:
        # Find value and index of largest element in the remainder of column j
        k = np.argmax(np.abs(A[i:m, j])) + i
        p = np.abs(A[k, j])
        if p <= tol:
            # The column is negligible, zero it out
            A[i:m, j] = 0.0
            j += 1
        else:
            # Remember the column index
            jb.append(j)
            if i != k:
                # Swap the i-th and k-th rows
                A[[i, k], j:n] = A[[k, i], j:n]
            # Divide the pivot row i by the pivot element A[i, j]
            A[i, j:n] = A[i, j:n] / A[i, j]
            # Subtract multiples of the pivot row from all the other rows
            for k in range(m):
                if k != i:
                    A[k, j:n] -= A[k, j] * A[i, j:n]
            i += 1
            j += 1
    # Finished
    return A, jb

示例:

A = np.array([[16.0, 2, 3, 13], [5, 11, 10, 8],
              [9, 7, 6, 12], [4, 14, 15, 1]])
Areduced, jb = rref(A)
print(f"The matrix as rank {len(jb)}")
print(Areduced)
    

0
投票

对于任何矩阵(具有满秩或不足),您可以循环遍历行(或列,这是等效的)并查看哪一行对排名有贡献。 选择前 n 行,您将得到一个最多具有 n 阶的矩阵。

from numpy.linalg import matrix_rank

def get_linind_rows(M):
    Mrows=[]
    Mranks=[]
    for i,Mrow in enumerate(M):
        Mrows.append(Mrow)
        Mrank = matrix_rank(Mrows) # this rank can be max i+1
        #print(i,Mrow,Mrank)
        Mranks.append(Mrank)
    Mranks_diff = np.diff(Mranks,prepend=0) # see where the rank increases by 1
    return M[Mranks_diff > 0] # select these rows as they are linear independent
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.