如何在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], [

我在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],
       [ 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