Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 计算矩阵子元素的Numpy例程?_Python_Numpy - Fatal编程技术网

Python 计算矩阵子元素的Numpy例程?

Python 计算矩阵子元素的Numpy例程?,python,numpy,Python,Numpy,我对使用numpy计算给定方阵的所有子矩阵感兴趣。有没有一种巧妙的方法可以使用数组切片来实现这一点?我设想可以旋转列、删除最后一列、旋转结果矩阵的行并删除最后一行,但我在numpy文档中没有发现任何表明这是可能的 (问:为什么这样做?答:我有一个很长的序列{M_n}对于相当大的矩阵,大约1000000 10000 x 10000个矩阵,我想计算每个矩阵的行列式。每个矩阵都是通过改变一个系数从它的前一个矩阵得到的。计算序列中第一个矩阵的行列式,然后计算差分det(M{n+1})会快得多-det(M

我对使用numpy计算给定方阵的所有子矩阵感兴趣。有没有一种巧妙的方法可以使用数组切片来实现这一点?我设想可以旋转列、删除最后一列、旋转结果矩阵的行并删除最后一行,但我在numpy文档中没有发现任何表明这是可能的

(问:为什么这样做?答:我有一个很长的序列{M_n}对于相当大的矩阵,大约1000000 10000 x 10000个矩阵,我想计算每个矩阵的行列式。每个矩阵都是通过改变一个系数从它的前一个矩阵得到的。计算序列中第一个矩阵的行列式,然后计算差分det(M{n+1})会快得多-det(M_n),是变化系数及其次项的乘积。)

这给出了
arr
的小调,删除了第一行和第二列:

In [36]: arr[np.array([0,2,3])[:,np.newaxis],np.array([0,1,3])]
Out[36]: 
array([[ 0.00750932,  0.47917318,  0.11755234],
       [ 0.5821906 ,  0.2060713 ,  0.0328739 ],
       [ 0.42066294,  0.88529916,  0.39389844]])
所以,你可以用这样的方法:

def minor(arr,i,j):
    # ith row, jth column removed
    return arr[np.array(list(range(i))+list(range(i+1,arr.shape[0])))[:,np.newaxis],
               np.array(list(range(j))+list(range(j+1,arr.shape[1])))]
first array:     second array:
[[0 0 0],        [[0, 1, 3],
 [2 2 2],         [0, 1, 3],
 [3 3 3]]         [0, 1, 3]]

关于其工作原理:

请注意索引数组的形状:

In [37]: np.array([0,2,3])[:,np.newaxis].shape
Out[37]: (3, 1)

In [38]: np.array([0,1,3]).shape
Out[38]: (3,)
使用
[:,np.newaxis]
只是给第一个数组赋形(3,1)

因为这些是numpy数组(而不是切片),所以numpy使用所谓的“花式”索引。花式索引的规则要求两个数组的形状相同,或者,当它们不相同时,使用广播来“放大”形状以便它们匹配

在这种情况下,第二个阵列的形状(3,)被抽运到(1,3)。但是 (3,1)和(1,3)不匹配,因此(3,1)被抽到(3,3),而(1,3)被抽到(3,3)

啊,最后,两个numpy阵列(广播后)的形状是一样的(3,3)

Numpy接受
arr[,]
并返回一个形状数组(毫不奇怪)(3,3)

返回数组的第(i,j)个元素将为

arr[(i,j)-th element of first array, (i,j)-th element of second array]
其中第一个和第二个数组(概念上)如下所示:

def minor(arr,i,j):
    # ith row, jth column removed
    return arr[np.array(list(range(i))+list(range(i+1,arr.shape[0])))[:,np.newaxis],
               np.array(list(range(j))+list(range(j+1,arr.shape[1])))]
first array:     second array:
[[0 0 0],        [[0, 1, 3],
 [2 2 2],         [0, 1, 3],
 [3 3 3]]         [0, 1, 3]]

如果你一次只改变矩阵的一个元素,你最好使用谢尔曼·莫里森式公式,():这样,你就有了N^2而不是N^3的复杂性。

联合国大学提供的答案已经很好了,优化算法@ev br的答案让我开始了一段有趣的旅程

我下面对这个问题的回答只是为了更清楚地表达我的意图

import numpy as np

arr = np.random.normal(0,1,(4,4))



def matrix_minor(arr, i, j):
    return np.delete(np.delete(arr,i,axis=0), j, axis=1)

# tests
arr

matrix_minor(arr, 0, 0)

matrix_minor(arr, 0, 1)

前几天我正在考虑这个问题,为此做了几次尝试和性能测试,所以我将分享我的发现

除了和提供的解决方案之外,我还提出了另外两个解决方案。 一个(
minor_mask()
)使用了基于掩码的Numpy数组索引,另一个(
minor_fortran()
)是我在使用好的ol'fortran时提出的解决方案,并对其进行了轻微修改,以使用Numba进行编译。将所有解决方案放在一起并执行一些基准测试:

示例代码
将numpy导入为np
进口麻木
def次要_面罩(A、i、j):
“”“基于NumPy花式索引的自有解决方案”“”
mask=np.one_like(A,dtype=bool)
掩码[i,:]=False
掩码[:,j]=假
小调=A[遮罩]。重塑(A.形状[0]-1,A.形状[1]-1)
德尔面具
返回小调
(A、i、j):
“”“由unutbu提供的解决方案”“”
归还[
np.array(list(range(i))+list(range(i+1,A.shape[0]))[:,np.newaxis],
np.array(list(range(j))+list(range(j+1,A.shape[1])),
]
定义小调保东(A、i、j):
“保东解决方案”
返回np.delete(np.delete(A,i,轴=0),j,轴=1)
@numba.njit()
def minor_fortran(A,i,j):
"""
基于Fortran例程的矩阵次要计算。
与numba很好地编译。
"""
次要=np.零((A.形状[0]-1,A.形状[0]-1))
对于范围内的m(A.形状[0]):
ishift=0
jshift=0
如果m>i:
ishift=1
对于范围内的n(A.形状[1]):
如果n>j:
jshift=1
小调[m-ishift,n-jshift]=A[m,n]
返回小调
性能测试 在我的机器(i5 9600K、32 GB RAM、openSUSE Leap 15.2、Python 3.8.9、Numpy 1.20.3、Numba 0.53.1、ipykernel 5.5.5)上,我使用以下代码得到了大小矩阵的以下结果:

m_small=np.arange(1e4).重塑(100100)
m_large=np.arange(1e8)。重塑(10000)
#首次运行Numba设置并比较结果
r1=小屏蔽(m大,10,11)
r2=小的(大的,10,11)
r3=小保东(大保东,10,11)
r4=小型fortran(大型,10,11)
打印(np.all(r1==r2))
#是的
打印(np.all(r2==r3))
#是的
打印(np.all(r3==r4))
#是的
#大矩阵
%timeit小调遮罩(m大、10、10)
#每个回路136 ms±1.95 ms(7次运行的平均值±标准偏差,每个10个回路)
%timeit minor_unutbu(m_large,10,10)
#每个回路247 ms±8.31 ms(7次运行的平均值±标准偏差,每个回路1次)
%timeit minor_pauldong(m_large,10,10)
#每个回路217 ms±3.79 ms(7次运行的平均值±标准偏差,每个回路1次)
%timeit minor_fortran(m_large,10,10)
#每个回路153 ms±1.26 ms(7次运行的平均值±标准偏差,每个10个回路)
#小矩阵
%timeit小屏幕遮罩(小屏幕,10,10)
#每个回路12.4µs±22.2 ns(7次运行的平均值±标准偏差,每个100000个回路)
%timeit minor_unutbu(m_small,10,10)
#每个回路36.7µs±140 ns(7次运行的平均值±标准偏差,每个10000个回路)
%timeit minor_pauldong(m_small,10,10)
#每个回路14.5µs±102纳秒(7次运行的平均值±标准偏差,每个100000个回路)
%timeit minor_fortran(m_small,10,10)
#每个回路10.4µs±34.2 ns(7次运行的平均值±标准偏差,每个100000个回路)
收尾 因此,我们共同发现@unutbu基于列表的方法在两个测试用例中的表现都最差,其次是@PaulDongs方法(尽管IMHO是所有解决方案中最干净的)。
奇特的索引方法似乎在小矩阵和大矩阵上都表现得很好,仅被com所超越