多维 numpy 数组的对角线
Diagonals of a multidimensional numpy array
是否有更 pythonic 的方式来执行以下操作:
import numpy as np
def diagonal(A):
(x,y,y) = A.shape
diags = []
for a in A: diags.append(np.diagonal(a))
result = np.vstack(diags)
assert result.shape == (x,y)
return result
假设 A
将是一个形状为 (m, n, n) 的数组(即 A
可以解释为 m
个形状为 [=15 的数组的集合=]), 这是一个快速的方法,return 是输入的视图:
In [14]: from numpy.lib.stride_tricks import as_strided
In [15]: def diags(a):
....: b = as_strided(a, strides=(a.strides[0], a.strides[1]+a.strides[2]), shape=(a.shape[0], a.shape[1]))
....: return b
....:
In [16]: a
Out[16]:
array([[[8, 6, 6, 5],
[1, 0, 3, 5],
[8, 1, 6, 7],
[2, 8, 7, 1]],
[[0, 8, 8, 0],
[1, 4, 2, 4],
[1, 4, 5, 6],
[2, 5, 2, 7]],
[[5, 2, 5, 2],
[2, 5, 7, 6],
[6, 5, 1, 8],
[7, 6, 5, 8]]])
In [17]: diags(a)
Out[17]:
array([[8, 0, 6, 1],
[0, 4, 5, 7],
[5, 5, 1, 8]])
当我说 return 值是一个 view 时,我的意思是它指的是与输入相同的底层内存。因此,如果您稍后就地更改 return 值,原始输入也会更改。例如,
In [24]: d = diags(a)
In [25]: d[0, :] = 99
In [26]: a[0]
Out[26]:
array([[99, 6, 6, 5],
[ 1, 99, 3, 5],
[ 8, 1, 99, 7],
[ 2, 8, 7, 99]])
方法 #1
A clean 方法将在输入数组的转置版本上使用 np.diagonal
,就像这样 -
np.diagonal(A.T)
基本上,我们用 A.T
翻转输入数组的维度,让 np.diagonal
使用最后两个轴来提取对角线元素,因为默认情况下它会使用取而代之的是前两个轴。最好的是这适用于任意维数的数组。
方法 #2
这是使用 advanced and basic indexing
-
组合的另一种方法
m,n = A.shape[:2]
out = A[np.arange(m)[:,None],np.eye(n,dtype=bool)]
也可以使用 basic indexing
-
进行一些重塑
out = A.reshape(m,-1)[:,np.eye(n,dtype=bool).ravel()]
样本运行-
In [87]: A
Out[87]:
array([[[73, 52, 62],
[20, 7, 7],
[ 1, 68, 89]],
[[15, 78, 98],
[24, 22, 35],
[19, 1, 91]],
[[ 5, 37, 64],
[22, 4, 43],
[84, 45, 12]],
[[24, 45, 42],
[70, 45, 1],
[ 6, 48, 60]]])
In [88]: np.diagonal(A.T)
Out[88]:
array([[73, 7, 89],
[15, 22, 91],
[ 5, 4, 12],
[24, 45, 60]])
In [89]: m,n = A.shape[:2]
In [90]: A[np.arange(m)[:,None],np.eye(n,dtype=bool)]
Out[90]:
array([[73, 7, 89],
[15, 22, 91],
[ 5, 4, 12],
[24, 45, 60]])
是否有更 pythonic 的方式来执行以下操作:
import numpy as np
def diagonal(A):
(x,y,y) = A.shape
diags = []
for a in A: diags.append(np.diagonal(a))
result = np.vstack(diags)
assert result.shape == (x,y)
return result
假设 A
将是一个形状为 (m, n, n) 的数组(即 A
可以解释为 m
个形状为 [=15 的数组的集合=]), 这是一个快速的方法,return 是输入的视图:
In [14]: from numpy.lib.stride_tricks import as_strided
In [15]: def diags(a):
....: b = as_strided(a, strides=(a.strides[0], a.strides[1]+a.strides[2]), shape=(a.shape[0], a.shape[1]))
....: return b
....:
In [16]: a
Out[16]:
array([[[8, 6, 6, 5],
[1, 0, 3, 5],
[8, 1, 6, 7],
[2, 8, 7, 1]],
[[0, 8, 8, 0],
[1, 4, 2, 4],
[1, 4, 5, 6],
[2, 5, 2, 7]],
[[5, 2, 5, 2],
[2, 5, 7, 6],
[6, 5, 1, 8],
[7, 6, 5, 8]]])
In [17]: diags(a)
Out[17]:
array([[8, 0, 6, 1],
[0, 4, 5, 7],
[5, 5, 1, 8]])
当我说 return 值是一个 view 时,我的意思是它指的是与输入相同的底层内存。因此,如果您稍后就地更改 return 值,原始输入也会更改。例如,
In [24]: d = diags(a)
In [25]: d[0, :] = 99
In [26]: a[0]
Out[26]:
array([[99, 6, 6, 5],
[ 1, 99, 3, 5],
[ 8, 1, 99, 7],
[ 2, 8, 7, 99]])
方法 #1
A clean 方法将在输入数组的转置版本上使用 np.diagonal
,就像这样 -
np.diagonal(A.T)
基本上,我们用 A.T
翻转输入数组的维度,让 np.diagonal
使用最后两个轴来提取对角线元素,因为默认情况下它会使用取而代之的是前两个轴。最好的是这适用于任意维数的数组。
方法 #2
这是使用 advanced and basic indexing
-
m,n = A.shape[:2]
out = A[np.arange(m)[:,None],np.eye(n,dtype=bool)]
也可以使用 basic indexing
-
out = A.reshape(m,-1)[:,np.eye(n,dtype=bool).ravel()]
样本运行-
In [87]: A
Out[87]:
array([[[73, 52, 62],
[20, 7, 7],
[ 1, 68, 89]],
[[15, 78, 98],
[24, 22, 35],
[19, 1, 91]],
[[ 5, 37, 64],
[22, 4, 43],
[84, 45, 12]],
[[24, 45, 42],
[70, 45, 1],
[ 6, 48, 60]]])
In [88]: np.diagonal(A.T)
Out[88]:
array([[73, 7, 89],
[15, 22, 91],
[ 5, 4, 12],
[24, 45, 60]])
In [89]: m,n = A.shape[:2]
In [90]: A[np.arange(m)[:,None],np.eye(n,dtype=bool)]
Out[90]:
array([[73, 7, 89],
[15, 22, 91],
[ 5, 4, 12],
[24, 45, 60]])