python - 多维数组行列式

标签 python numpy multidimensional-array

我正在尝试计算一个 numpy 数组 M 的行列式,其中 np.shape(M) = (N, L, L) 类似于:

import numpy as np

M = np.random.rand(1000*10*10).reshape(1000, 10, 10)
dm = np.zeros(1000)
for _ in xrange(len(dm)):
    dm[_] = np.linalg.det(M[_])

有没有不循环的方法? “N”比“L”大几个数量级。我想到了类似的东西:

np.apply_over_axes(np.linalg.det(M), axis=0) 

有没有更快的方法做我想做的事?我猜循环开销是一个性能瓶颈,因为小矩阵的行列式是一个相对便宜的操作(或者我错了吗?)。

最佳答案

您需要修改np.linalg.det 以获得速度。这个想法是 det() 是一个 Python 函数,它首先进行大量检查,然后调用 fortran 例程,并进行一些数组计算以获得结果。

这是来自 numpy 的代码:

def slogdet(a):
    a = asarray(a)
    _assertRank2(a)
    _assertSquareness(a)
    t, result_t = _commonType(a)
    a = _fastCopyAndTranspose(t, a)
    a = _to_native_byte_order(a)
    n = a.shape[0]
    if isComplexType(t):
        lapack_routine = lapack_lite.zgetrf
    else:
        lapack_routine = lapack_lite.dgetrf
    pivots = zeros((n,), fortran_int)
    results = lapack_routine(n, n, a, n, pivots, 0)
    info = results['info']
    if (info < 0):
        raise TypeError, "Illegal input to Fortran routine"
    elif (info > 0):
        return (t(0.0), _realType(t)(-Inf))
    sign = 1. - 2. * (add.reduce(pivots != arange(1, n + 1)) % 2)
    d = diagonal(a)
    absd = absolute(d)
    sign *= multiply.reduce(d / absd)
    log(absd, absd)
    logdet = add.reduce(absd, axis=-1)
    return sign, logdet

def det(a):
    sign, logdet = slogdet(a)
    return sign * exp(logdet)

为了加速这个函数,你可以省略检查(保持输入正确成为你的责任),并将 fortran 结果收集在一个数组中,并在没有 for 循环的情况下对所有小数组进行最终计算。

这是我的结果:

import numpy as np
from numpy.core import intc
from numpy.linalg import lapack_lite

N = 1000
M = np.random.rand(N*10*10).reshape(N, 10, 10)

def dets(a):
    length = a.shape[0]
    dm = np.zeros(length)
    for i in xrange(length):
        dm[i] = np.linalg.det(M[i])
    return dm

def dets_fast(a):
    m = a.shape[0]
    n = a.shape[1]
    lapack_routine = lapack_lite.dgetrf
    pivots = np.zeros((m, n), intc)
    flags = np.arange(1, n + 1).reshape(1, -1)
    for i in xrange(m):
        tmp = a[i]
        lapack_routine(n, n, tmp, n, pivots[i], 0)
    sign = 1. - 2. * (np.add.reduce(pivots != flags, axis=1) % 2)
    idx = np.arange(n)
    d = a[:, idx, idx]
    absd = np.absolute(d)
    sign *= np.multiply.reduce(d / absd, axis=1)
    np.log(absd, absd)
    logdet = np.add.reduce(absd, axis=-1)
    return sign * np.exp(logdet)

print np.allclose(dets(M), dets_fast(M.copy()))

速度是:

timeit dets(M)
10 loops, best of 3: 159 ms per loop

timeit dets_fast(M)
100 loops, best of 3: 10.7 ms per loop

因此,通过这样做,您可以将速度提高 15 倍。这是一个没有任何编译代码的好结果。

注意:我省略了 fortran 例程的错误检查。

关于python - 多维数组行列式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13393733/

相关文章:

python - 如何在这段代码上应用 PyQt QThread

graph - Z 符号 : Representation of a 2D array

python - 参数化导入语句

PHP xmlrpc 客户端和 Python 2.5 xmlrpc 服务器 : incomplete data and Connection reset by peer error

python - 使用 NumPy float 参数和 dict_values

python - 如何从元素列表开始进行回归

python - 如何在不在 NumPy 中复制的情况下展平多维数组的轴?

python - 我该如何优化这段代码?以及一般如何优化 Python for 循环?

python - 返回给定字符串语言的最佳方法

python - 获取排序矩阵索引的简单方法