2013-04-09 152 views
3

目前我使用下面的代碼與第i行第j列去除,以獲得小矩陣,但剖析我的代碼後,它似乎是在我的代碼的主要瓶頸之一。有沒有更高效的方法?numpy的更高效的小矩陣

def submatrix(A, i, j): 
    logger.debug('submatrix(%r, %r, %r)', A, i, j) 
    B = empty(shape=tuple(x - 1 for x in A.shape), dtype=int) 
    B[:i, :j] = A[:i, :j] 
    B[i:, :j] = A[i+1:, :j] 
    B[:i, j:] = A[:i, j+1:] 
    B[i:, j:] = A[i+1:, j+1:] 
    return B 

     25015049 function calls (24599369 primitive calls) in 44.587 seconds 

    Ordered by: internal time 

    ncalls tottime percall cumtime percall filename:lineno(function) 
    3983040 15.541 0.000 20.719 0.000 defmatrix.py:301(__getitem__) 
    415680 10.216 0.000 33.069 0.000 hill.py:127(submatrix) 
415686/6 3.232 0.000 44.578 7.430 hill.py:112(det) 

編輯:海梅提供了近似使用常規逆和行列式模塊化逆一個很好的方式,但是用大基地(模256在我的情況),不準確,就足以使整個事情沒有實際意義的。主要時間片似乎實際上是的GetItem在numpy的,但我相信,通過這些線路引起的:

B[:i, :j] = A[:i, :j] 
    B[i:, :j] = A[i+1:, :j] 
    B[:i, j:] = A[:i, j+1:] 
    B[i:, j:] = A[i+1:, j+1:] 

這是可能的瓶頸並不在內存中拷貝矩陣,但矩陣條目訪問。

+0

作爲@Bitwise指出了他的答案,沒有太多的速度高達走動內存來獲得。您可以通過在地方所做的操作數據做小至少25%的洗牌,是一種選擇?另外,你需要什麼這個子矩陣?使用子矩陣修改代碼忽略相應的行和列比實際刪除它們更容易。 – Jaime 2013-04-09 16:05:35

+1

是否有可能產生子陣圖?我並不需要副本的副本,但我不確定是否可以隨意切片,因爲我對numpy不熟悉。 – darkfeline 2013-04-09 16:16:48

+0

一般來說不,你不能看到子矩陣。之後你對子矩陣做什麼? – Jaime 2013-04-09 16:31:48

回答

1

嗯......你只複製矩陣,那麼它可能會很困難得多加快,但有一兩件事你可以嘗試是驗證A是在一個連續的內存塊,這可能是速度訪問C代碼。看看numpy.ascontiguousarray()

1

據我所知,submatrix只是刪除了第i行和第j列。你可以用np.delete

i = 3 
j = 4 
a = np.arange(100).reshape(10,10) 
b = np.delete(np.delete(a, i, 0), j, 1) 

做到這一點,但,對於羅先@Jaime引用,這其實是慢:-/

timeit submatrix(a, i, j) 
#10000 loops, best of 3: 23.2 us per loop 

timeit subdel(a, i, j) 
#10000 loops, best of 3: 42.6 us per loop 

但是在這裏我要離開這個現在。

+0

這將創建一箇中間數組沒有'我'第th行,然後刪除其第j列,所以它可能會兩次一樣慢。 – Jaime 2013-04-09 16:04:10

+0

@Jaime你是對的我只是在計時。可以刪除一行和一列? – askewchan 2013-04-09 16:04:49

+0

不是我所知道的...... – Jaime 2013-04-09 16:05:19

1

計算使用決定因素矩陣的逆是一個非常緩慢的辦法,無論你怎麼做的小矩陣。讓我們一個愚蠢的例子:

a = np.array([[3, 0, 2], 
       [2, 0, -2], 
       [0, 1, 1]]) 

您可以快速計算逆爲:

>>> np.linalg.inv(a) 
array([[ 0.2, 0.2, 0. ], 
     [-0.2, 0.3, 1. ], 
     [ 0.2, -0.3, -0. ]]) 

但要計算模逆,你需要把它作爲一個整數矩陣由一個整數因子分開。當然,該整數因素將是決定因素,這樣你就可以做到以下幾點:

>>> np.linalg.inv(a) * np.linalg.det(a) 
array([[ 2., 2., 0.], 
     [ -2., 3., 10.], 
     [ 2., -3., -0.]]) 

a倒數就是這個整數矩陣,由a行列式分。作爲一個功能,你可以這樣做:

def extended_euclidean_algorithm(a, b) : 
    """ 
    Computes a solution to a x + b y = gcd(a,b), as well as gcd(a,b), 
    using the extended Euclidean algorithm. 
    """ 
    if b == 0 : 
     return 1, 0, a 
    else : 
     x, y, gcd = extended_euclidean_algorithm(b, a % b) 
     return y, x - y * (a // b), gcd 

def mmi(a, m) : 
    """ 
    Computes the modular multiplicative inverse of a modulo m, using the 
    extended Euclidean algorithm. 
    """ 
    x, y, gcd = extended_euclidean_algorithm(a, m) 
    if gcd == 1 : 
     return x % m 
    else : 
     return None 

def modular_inv(a, m): 
    det_a = np.linalg.det(a) 
    inv_a = np.linalg.inv(a) * det_a 
    det_a = np.rint(det_a).astype(int) 
    inv_a = np.rint(inv_a).astype(int) 
    return ((inv_a % m) * mmi(det_a, m)) % m 

現在:

>>> a = np.random.randint(10, size=(10, 10)) 
>>> b = modular_inv(a, 7) 
>>> a.dot(b) % 7 
array([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
     [0, 1, 0, 0, 0, 0, 0, 0, 0, 0], 
     [0, 0, 1, 0, 0, 0, 0, 0, 0, 0], 
     [0, 0, 0, 1, 0, 0, 0, 0, 0, 0], 
     [0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 
     [0, 0, 0, 0, 0, 1, 0, 0, 0, 0], 
     [0, 0, 0, 0, 0, 0, 1, 0, 0, 0], 
     [0, 0, 0, 0, 0, 0, 0, 1, 0, 0], 
     [0, 0, 0, 0, 0, 0, 0, 0, 1, 0], 
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 1]]) 
+0

這聽起來不錯,但我認爲,因爲我在模256工作,所以精確的浮點數正在讓您的答案變得糟糕透頂。 – darkfeline 2013-04-09 19:48:42