2013-04-09 101 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