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