在Numpy中制作特殊的对角矩阵

时间:2013-08-02 21:41:03

标签: python arrays numpy matrix toeplitz

我正在尝试创建一个看起来像这样的numpy数组:

[a b c       ]
[  a b c     ]
[    a b c   ]
[      a b c ] 

所以这涉及更新主对角线和它上面的两条对角线。

这样做的有效方法是什么?

5 个答案:

答案 0 :(得分:19)

您可以使用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.]])

答案 1 :(得分:6)

这是Toeplitz matrix的示例 - 您可以使用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]]

答案 2 :(得分:4)

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将是更好的选择。

答案 3 :(得分:1)

我无法发表评论,但我想碰碰一下ali_m的答案是迄今为止最有效的,因为scipy会为您处理事情。

例如,使用大小为n,m = 1200的矩阵,重复添加np.diag()个调用将花费~6.14s,Saullo GP Castro的答案将花费~7.7s,而scipy.linalg.toeplitz(np.arange(N), np.arange(N))则花费1.57ms

答案 4 :(得分:0)

使用我对这个问题的回答:changing the values of the diagonal of a matrix in 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