簡體   English   中英

是否有可能像在Matlab中一樣快地計算Python中的稀疏矩陣的逆?

[英]Is it possible to compute an inverse of sparse matrix in Python as fast as in Matlab?

Matlab使用稀疏命令計算對角矩陣的倒數需要0.02秒。

P = diag(1:10000);
P = sparse(P);
tic;
A = inv(P);
toc

但是,對於Python代碼,它需要永遠 - 幾分鍾。

import numpy as np
import time

startTime = time.time()
P = np.diag(range(1,10000))
A = np.linalg.inv(P)
runningTime = (time.time()-startTime)/60
print "The script was running for %f minutes" % runningTime

我試圖使用Scipy.sparse模塊,但它沒有幫助。 運行時間下降,但只有40秒。

import numpy as np
import time
import scipy.sparse as sps
import scipy.sparse.linalg as spsl

startTime = time.time()
P = np.diag(range(1,10000))
P_sps = sps.coo_matrix(P)
A = spsl.inv(P_sps)
runningTime = (time.time()-startTime)/60
print "The script was running for %f minutes" % runningTime

是否可以像在Matlab中運行一樣快地運行代碼?

這是答案。 當您在matlab中為稀疏矩陣運行inv時,matlab會檢查矩陣的不同屬性以優化計算。 對於稀疏對角矩陣,您可以運行以下代碼來查看matlab正在做什么

n = 10000;
a = diag(1:n);
a = sparse(a);
I = speye(n,n);
spparms('spumoni',1);
ainv = inv(a);
spparms('spumoni',0);

Matlab將打印以下內容:

sp\: bandwidth = 0+1+0.
sp\: is A diagonal? yes.
sp\: do a diagonal solve.

所以matlab只反轉對角線。

Scipy如何反轉矩陣? 這里我們有代碼

...
from scipy.sparse.linalg import spsolve
...

def inv(A):
    """
    Some comments...
    """
    I = speye(A.shape[0], A.shape[1], dtype=A.dtype, format=A.format)
    Ainv = spsolve(A, I)
    return Ainv

spsolve

    # Cover the case where b is also a matrix
    Afactsolve = factorized(A)
    tempj = empty(M, dtype=int)
    x = A.__class__(b.shape)
    for j in range(b.shape[1]):
        xj = Afactsolve(squeeze(b[:, j].toarray()))
        w = where(xj != 0.0)[0]
        tempj.fill(j)
        x = x + A.__class__((xj[w], (w, tempj[:len(w)])),
                            shape=b.shape, dtype=A.dtype)

即,scipy factorize A然后求解一組線性系統,其中右側是坐標向量(形成單位矩陣)。 在矩陣中排序所有解,我們得到初始矩陣的逆。

如果matlab被利用矩陣的對角線結構,但scipy不是(當然scipy也使用矩陣的結構,但效率較低,至少對於這個例子而言),matlab應該快得多。

編輯可以肯定的是,正如@ P.Escondido所提議的那樣,我們將嘗試在矩陣A中進行微小的修改,以便在矩陣不是對角線時跟蹤matlab過程:

n = 10000; a = diag(1:n); a = sparse(a); ainv = sparse(n,n);
spparms('spumoni',1);
a(100,10) = 500; a(10,1000) = 200; 
ainv = inv(a);
spparms('spumoni',0);

它打印出以下內容:

sp\: bandwidth = 90+1+990.
sp\: is A diagonal? no.
sp\: is band density (0.00) > bandden (0.50) to try banded solver? no.
sp\: is A triangular? no.
sp\: is A morally triangular? yes.
sp\: permute and solve.
sp\: sprealloc in sptsolve: 10000 10000 10000 15001

splu()怎么樣,它更快但需要一個密集的數組並返回密集的數組:

創建一個隨機矩陣:

import numpy as np
import time
import scipy.sparse as sps
import scipy.sparse.linalg as spsl
from numpy.random import randint
N = 1000
i = np.arange(N)
j = np.arange(N)
v = np.ones(N)

i2 = randint(0, N, N)
j2 = randint(0, N, N)
v2 = np.random.rand(N)

i = np.concatenate((i, i2))
j = np.concatenate((j, j2))
v = np.concatenate((v, v2))

A = sps.coo_matrix((v, (i, j)))
A = A.tocsc()

%time B = spsl.inv(A)

通過splu()計算逆矩陣:

%%time
lu = spsl.splu(A)
eye = np.eye(N)
B2 = lu.solve(eye)

檢查結果:

np.allclose(B.todense(), B2.T)

這是%時間輸出:

inv: 2.39 s
splv: 193 ms

您正在從軟件中提取關鍵信息:矩陣是對角線的事實使得它非常容易反轉:您只需反轉其對角線的每個元素:

P = np.diag(range(1,10000))
A = np.diag(1.0/np.arange(1,10000))

當然,這僅適用於對角矩陣......

如果您嘗試使用,結果會更好:

import numpy as np
import time
import scipy.sparse as sps
import scipy.sparse.linalg as spsl

P = np.diag(range(1,10000))
P_sps = sps.coo_matrix(P)
startTime = time.time()
A = spsl.inv(P_sps)
runningTime = (time.time()-startTime)/60
print "The script was running for %f minutes" % runningTime

現在您可以與您的matlab腳本進行比較。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM