如何在Python中只添加数组的对角线?
我在Python上有一个数组,如下所示:如何在Python中只添加数组的对角线?,python,numpy,scipy,Python,Numpy,Scipy,我在Python上有一个数组,如下所示: array([[ 0.57733218, 0.09794384, 0.44497735], [ 0.87061284, 0.10253493, 0.56643557], [ 0.76358739, 0.44902046, 0.86064797]]) 我希望将标量值20添加到数组的对角线,以便输出为: array([[ 20.57733218, 0.09794384, 0.44497735], [
array([[ 0.57733218, 0.09794384, 0.44497735],
[ 0.87061284, 0.10253493, 0.56643557],
[ 0.76358739, 0.44902046, 0.86064797]])
我希望将标量值20添加到数组的对角线,以便输出为:
array([[ 20.57733218, 0.09794384, 0.44497735],
[ 0.87061284, 20.10253493, 0.56643557],
[ 0.76358739, 0.44902046, 20.86064797]])
因为我可能也在处理非常大的矩阵数组,
按照公认的解决方案,通过赋值操作进行对角线加法的最有效方法是什么?一种方法是在具有适当步长的平坦切片上赋值-
In [233]: a
Out[233]:
array([[ 0.57733218, 0.09794384, 0.44497735],
[ 0.87061284, 0.10253493, 0.56643557],
[ 0.76358739, 0.44902046, 0.86064797]])
In [234]: a.flat[::a.shape[1]+1] += 20
In [235]: a
Out[235]:
array([[ 20.57733218, 0.09794384, 0.44497735],
[ 0.87061284, 20.10253493, 0.56643557],
[ 0.76358739, 0.44902046, 20.86064797]])
我们还可以使用ndarray.ravel()
获取展平视图,然后指定-
a.ravel()[::a.shape[1]+1] += 20
另一种方法是使用np.einsum
,它为我们提供了对角元素的视图-
In [269]: a
Out[269]:
array([[ 0.57733218, 0.09794384, 0.44497735],
[ 0.87061284, 0.10253493, 0.56643557],
[ 0.76358739, 0.44902046, 0.86064797]])
In [270]: d = np.einsum('ii->i', a)
In [271]: d += 20
In [272]: a
Out[272]:
array([[ 20.57733218, 0.09794384, 0.44497735],
[ 0.87061284, 20.10253493, 0.56643557],
[ 0.76358739, 0.44902046, 20.86064797]])
标杆管理
鉴于
a
是我们要更新的数组,我们可以使用和:
因此,我们首先使用
a.diagonal()
获取a
的对角线,然后将20
添加到对角线的每个元素中。我们使用np.fill_diagonal(..)
来设置对角线的元素。您还可以使用np.eye
创建一个对角线矩阵,并将其与合适的常数c
相乘
np.eye(n, dtype=int) * c # n x n matrix with diagonal part being c
然后,将其添加到矩阵a
a = np.array([[ 0.57733218, 0.09794384, 0.44497735],
[ 0.87061284, 0.10253493, 0.56643557],
[ 0.76358739, 0.44902046, 0.86064797]])
a += np.eye(3) * 20
或者用np.eye(3,dtype=bool)
制作一个面具,这样你就可以用它来选择对角线部分并像这样添加到上面
a[np.eye(3, dtype=bool)] += 20
感谢Divakar关于使用面具的建议和Willem Van Onsem关于让答案清晰的建议
编辑:当数据量较大时,Willem和Divakar的方法都比这快得多。注意到nD数组是正方形(一般情况下是长方体),您可以提取对角线元素的索引,通过索引到数组中获得对角线元素的原始值,然后加上你想要的常数;然后使用我们从中获得的索引,通过索引到数组中来更新原始对角线值,如:
如果要在一行中完成,则:
In [36]: arr[np.diag_indices(arr.shape[0])] = arr[np.diag_indices_from(arr)] + 20
p.S.请注意,这会修改原始数组。也许您应该在此处添加
a+=
,以便清楚地更新a
。或者简单地说:a[np.eye(n,dtype=bool)]+=20
。对于大型矩阵形状,用于掩蔽的布尔数组将不会占用太多内存。@WillemVanOnsem感谢您的建议!考虑到@Divakar的时间测试,我喜欢这个选项,因为它是提供问题解决方案的最简洁的表达,尽管我是一个einsum的忠实粉丝。
a[np.eye(3, dtype=bool)] += 20
In [28]: arr
Out[28]:
array([[ 0.57733218, 0.09794384, 0.44497735],
[ 0.87061284, 0.10253493, 0.56643557],
[ 0.76358739, 0.44902046, 0.86064797]])
In [29]: new_diag_vals = arr[np.diag_indices_from(arr)] + 20
In [30]: arr[np.diag_indices(arr.shape[0])] = new_diag_vals
In [31]: arr
Out[31]:
array([[ 20.57733218, 0.09794384, 0.44497735],
[ 0.87061284, 20.10253493, 0.56643557],
[ 0.76358739, 0.44902046, 20.86064797]])
In [36]: arr[np.diag_indices(arr.shape[0])] = arr[np.diag_indices_from(arr)] + 20