我正在尝试制作一个如下所示的 numpy 数组:
[a b c ]
[ a b c ]
[ a b c ]
[ a b c ]
所以这涉及更新主对角线和它上面的两条对角线。
这样做的有效方法是什么?
您可以使用np.indices
来获取数组的索引,然后将值分配到您想要的位置。
a = np.zeros((5,10))
i,j = np.indices(a.shape)
i,j
分别是行和列索引。
a[i==j] = 1.
a[i==j-1] = 2.
a[i==j-2] = 3.
将导致:
array([[ 1., 2., 3., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 1., 2., 3., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 1., 2., 3., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 1., 2., 3., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 1., 2., 3., 0., 0., 0.]])
这是Toeplitz 矩阵的一个示例- 您可以使用以下方法构造它scipy.linalg.toeplitz
:
import numpy as np
from scipy.linalg import toeplitz
first_row = np.array([1, 2, 3, 0, 0, 0])
first_col = np.array([1, 0, 0, 0])
print(toeplitz(first_col, first_row))
# [[1 2 3 0 0 0]
# [0 1 2 3 0 0]
# [0 0 1 2 3 0]
# [0 0 0 1 2 3]]
import numpy as np
def using_tile_and_stride():
arr = np.tile(np.array([10,20,30,0,0,0], dtype='float'), (4,1))
row_stride, col_stride = arr.strides
arr.strides = row_stride-col_stride, col_stride
return arr
In [108]: using_tile_and_stride()
Out[108]:
array([[ 10., 20., 30., 0., 0., 0.],
[ 0., 10., 20., 30., 0., 0.],
[ 0., 0., 10., 20., 30., 0.],
[ 0., 0., 0., 10., 20., 30.]])
其他较慢的替代方案包括:
import numpy as np
import numpy.lib.stride_tricks as stride
def using_put():
arr = np.zeros((4,6), dtype='float')
a, b, c = 10, 20, 30
nrows, ncols = arr.shape
ind = (np.arange(3) + np.arange(0,(ncols+1)*nrows,ncols+1)[:,np.newaxis]).ravel()
arr.put(ind, [a, b, c])
return arr
def using_strides():
return np.flipud(stride.as_strided(
np.array([0, 0, 0, 10, 20, 30, 0, 0, 0], dtype='float'),
shape=(4, 6), strides = (8, 8)))
如果您使用using_tile_and_stride
,请注意该数组仅适用于只读目的。否则,如果您尝试修改数组,当多个数组位置同时更改时,您可能会感到惊讶:
In [32]: arr = using_tile_and_stride()
In [33]: arr[0, -1] = 100
In [34]: arr
Out[34]:
array([[ 10., 20., 30., 0., 100.],
[ 100., 10., 20., 30., 0.],
[ 0., 0., 10., 20., 30.],
[ 30., 0., 0., 10., 20.]])
np.ascontiguousarray(arr)
你可以通过返回而不是仅仅返回来解决这个问题arr
,但是using_tile_and_stride
会比using_put
. 所以如果你打算修改数组,using_put
会是一个更好的选择。
我还不能发表评论,但我想强调 ali_m 的答案是迄今为止最有效的,因为 scipy 会为你处理事情。
例如,对于一个大小为 的矩阵n,m = 1200
,重复添加np.diag()
调用~6.14s
take 、Saullo GP Castro 的答案 take~7.7s
和scipy.linalg.toeplitz(np.arange(N), np.arange(N))
take 1.57ms
。
使用我对这个问题的回答:更改 numpy 中矩阵的对角线的值,您可以进行一些棘手的切片以查看每个对角线,然后进行分配。在这种情况下,它只是:
import numpy as np
A = np.zeros((4,6))
# main diagonal
A.flat[:A.shape[1]**2:A.shape[1]+1] = a
# first superdiagonal
A.flat[1:max(0,A.shape[1]-1)*A.shape[1]:A.shape[1]+1] = b
# second superdiagonal
A.flat[2:max(0,A.shape[1]-2)*A.shape[1]:A.shape[1]+1] = c