python - 如何将数组替换为numpy数组python的对角线

标签 python numpy

我有一个数组

import numpy as np
X = np.array([[0.7513,  0.6991,    0.5472,    0.2575],
          [0.2551,  0.8909,    0.1386,    0.8407],
          [0.5060,  0.9593,    0.1493,    0.2543],
          [0.5060,  0.9593,    0.1493,    0.2543]])
y = np.array([[1,2,3,4]])

如何用 y 替换 X 的对角线。我们可以写一个循环,但有什么更快的方法吗?

最佳答案

一种快速可靠的方法是np.einsum:

>>> diag_view = np.einsum('ii->i', X)

这将创建一个对角线 View :

>>> diag_view
array([0.7513, 0.8909, 0.1493, 0.2543])

这个 View 是可写的:

>>> diag_view[None] = y
>>> X                                                                                                               
array([[1.    , 0.6991, 0.5472, 0.2575],                                                                            
       [0.2551, 2.    , 0.1386, 0.8407],                                                                            
       [0.506 , 0.9593, 3.    , 0.2543],                                                                            
       [0.506 , 0.9593, 0.1493, 4.    ]])                                                                           

这适用于连续和非连续数组并且非常快:

contiguous:
loop          21.146424998732982
diag_indices  2.595232878000388
einsum        1.0271988900003635
flatten       1.5372659160002513

non contiguous:
loop          20.133818001340842
diag_indices  2.618005960001028
einsum        1.0305795049989683
Traceback (most recent call last): <- flatten does not work here
...

它是如何工作的?在引擎盖下 einsum 做了@Julien 技巧的高级版本:它增加了 arr 的步幅:

>>> arr.strides
(3200, 16)
>>> np.einsum('ii->i', arr).strides
(3216,)

人们可以说服自己,只要 arr 是大步组织的,这将始终有效,numpy 数组就是这种情况。

虽然 einsum 的这种用法非常巧妙,但如果不知道,也几乎不可能找到。所以传播这个词吧!

重新创建时间和崩溃的代码:

import numpy as np

n = 100
arr = np.zeros((n, n))
replace = np.ones(n)

def loop():
    for i in range(len(arr)):
        arr[i,i] = replace[i]

def other():
    l = len(arr)
    arr.shape = -1
    arr[::l+1] = replace
    arr.shape = l,l

def di():
    arr[np.diag_indices(arr.shape[0])] = replace

def es():
    np.einsum('ii->i', arr)[...] = replace

from timeit import timeit
print('\ncontiguous:')
print('loop         ', timeit(loop, number=1000)*1000)
print('diag_indices ', timeit(di))
print('einsum       ', timeit(es))
print('flatten      ', timeit(other))

arr = np.zeros((2*n, 2*n))[::2, ::2]
print('\nnon contiguous:')
print('loop         ', timeit(loop, number=1000)*1000)
print('diag_indices ', timeit(di))
print('einsum       ', timeit(es))
print('flatten      ', timeit(other))

关于python - 如何将数组替换为numpy数组python的对角线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52825926/

相关文章:

python - 删除和重新插入空格

python - 傅里叶空间滤波

python - 逆小波变换[/xpost信号处理]

python - 在Python中格式化具有多个浮点值的字符串

python - 隐式访问SQLAlchemy类字段并修复 'object is not subscriptable'错误

python - 将重复元素设置为零

python - 在numpy中组合多维数据

python - 不同形状数组的输出索引 Python

python - 我怎么知道我的变量是什么类型?

Python:PBS 提交,如果我更改脚本会怎样?