使用 numpy 从对角线值创建数组堆栈
Create stack of arrays from diagonal values using numpy
我正在尝试在 python 中进行一些矩阵计算,当我尝试使用堆叠数组而不是简单的 for 循环来加速我的代码时遇到了一个问题。我需要在对角线上创建一个带有值(以一维数组形式给出)的二维数组,但无法找到一种使用堆叠数组的聪明方法。
在旧的(循环)版本中,我使用了 np.diag() 方法,如果我将值作为一维数组作为输入。但是,当我切换到堆叠数组时,我的输入不再是一维数组,因此 np.diag() 方法 returns 是我的二维输入对角线的副本。
具有一维输入的旧版本:
import numpy as np
vals = np.array([1,2,3])
mat = np.diag(vals)
print(mat.shape)
Out: (3, 3)
带有 2D 输入的新版本:
vals_stack = np.repeat(np.expand_dims(vals, axis=0), 5, axis=0)
# btw: is there a better way to repeat/stack my array?
mat_stack = np.diag(vals_stack)
print(mat_stack.shape)
Out: (3,)
所以你可以看到 np.diag() returns 一个一维数组(正如文档中预期的那样),但我实际上需要一堆二维数组。所以 mat_stack 的形状必须是 (7,3,3) 而不是 (3,)。在numpy中有什么功能吗?或者我是否必须像这样遍历该附加维度:
def mydiag(stack):
diag = np.zeros([stack.shape[0], stack.shape[1], stack.shape[1]])
for i in np.arange(stack.shape[0]):
diag[i,:,:] = np.diag([stack[i,:].ravel()])
return diag
在 numpy 中你应该使用 apply_along_axis
。在您的特定案例 (here) 的文档末尾甚至还有一个示例。所以答案是:
np.apply_along_axis(np.diag, -1, vals_stack)
更像 pythonic 的方式是这样的:
[np.diag(row) for row in vals_stack]
这是你的想法吗:
In [499]: x = np.arange(12).reshape(4,3)
In [500]: X = np.zeros((4,3,3),int)
In [501]: X[np.arange(4)[:,None],np.arange(3), np.arange(3)] = x
In [502]: X
Out[502]:
array([[[ 0, 0, 0],
[ 0, 1, 0],
[ 0, 0, 2]],
[[ 3, 0, 0],
[ 0, 4, 0],
[ 0, 0, 5]],
[[ 6, 0, 0],
[ 0, 7, 0],
[ 0, 0, 8]],
[[ 9, 0, 0],
[ 0, 10, 0],
[ 0, 0, 11]]])
X[0,np.arange(3), np.arange(3)]
索引第一个平面上的对角线。 np.arange(4)[:,None]
是一个 (4,1) 数组,它使用 (3,) 广播以索引 (4,3) 块,匹配 x
.
的大小
我正在尝试在 python 中进行一些矩阵计算,当我尝试使用堆叠数组而不是简单的 for 循环来加速我的代码时遇到了一个问题。我需要在对角线上创建一个带有值(以一维数组形式给出)的二维数组,但无法找到一种使用堆叠数组的聪明方法。
在旧的(循环)版本中,我使用了 np.diag() 方法,如果我将值作为一维数组作为输入。但是,当我切换到堆叠数组时,我的输入不再是一维数组,因此 np.diag() 方法 returns 是我的二维输入对角线的副本。
具有一维输入的旧版本:
import numpy as np
vals = np.array([1,2,3])
mat = np.diag(vals)
print(mat.shape)
Out: (3, 3)
带有 2D 输入的新版本:
vals_stack = np.repeat(np.expand_dims(vals, axis=0), 5, axis=0)
# btw: is there a better way to repeat/stack my array?
mat_stack = np.diag(vals_stack)
print(mat_stack.shape)
Out: (3,)
所以你可以看到 np.diag() returns 一个一维数组(正如文档中预期的那样),但我实际上需要一堆二维数组。所以 mat_stack 的形状必须是 (7,3,3) 而不是 (3,)。在numpy中有什么功能吗?或者我是否必须像这样遍历该附加维度:
def mydiag(stack):
diag = np.zeros([stack.shape[0], stack.shape[1], stack.shape[1]])
for i in np.arange(stack.shape[0]):
diag[i,:,:] = np.diag([stack[i,:].ravel()])
return diag
在 numpy 中你应该使用 apply_along_axis
。在您的特定案例 (here) 的文档末尾甚至还有一个示例。所以答案是:
np.apply_along_axis(np.diag, -1, vals_stack)
更像 pythonic 的方式是这样的:
[np.diag(row) for row in vals_stack]
这是你的想法吗:
In [499]: x = np.arange(12).reshape(4,3)
In [500]: X = np.zeros((4,3,3),int)
In [501]: X[np.arange(4)[:,None],np.arange(3), np.arange(3)] = x
In [502]: X
Out[502]:
array([[[ 0, 0, 0],
[ 0, 1, 0],
[ 0, 0, 2]],
[[ 3, 0, 0],
[ 0, 4, 0],
[ 0, 0, 5]],
[[ 6, 0, 0],
[ 0, 7, 0],
[ 0, 0, 8]],
[[ 9, 0, 0],
[ 0, 10, 0],
[ 0, 0, 11]]])
X[0,np.arange(3), np.arange(3)]
索引第一个平面上的对角线。 np.arange(4)[:,None]
是一个 (4,1) 数组,它使用 (3,) 广播以索引 (4,3) 块,匹配 x
.