不使用for循环构建对角矩阵

时间:2014-03-23 21:31:48

标签: python numpy scipy diagonal

我试图在不使用for循环的情况下在Python中构建以下矩阵:

A 
 [[ 0.1  0.2  0.   0.   0. ]
 [ 1.   2.   3.   0.   0. ]
 [ 0.   1.   2.   3.   0. ]
 [ 0.   0.   1.   2.   3. ]
 [ 0.   0.   0.   4.   5. ]]

我在NumPy中尝试了fill_diagonal方法(参见下面的矩阵B),但它没有给出矩阵A中显示的相同矩阵:

B 
 [[ 1.   0.2  0.   0.   0. ]
 [ 0.   2.   0.   0.   0. ]
 [ 0.   0.   3.   0.   0. ]
 [ 0.   0.   0.   1.   0. ]
 [ 0.   0.   0.   4.   5. ]]

以下是我用来构造矩阵的Python代码:

import numpy as np
import scipy.linalg as sp   # maybe use scipy to build diagonal matrix?

#---- build diagonal square array using "for" loop
m = 5

A = np.zeros((m, m))

A[0, 0] = 0.1
A[0, 1] = 0.2

for i in range(1, m-1):
    A[i, i-1] = 1   # m-1
    A[i, i] = 2     # m
    A[i, i+1] = 3   # m+1

A[m-1, m-2] = 4
A[m-1, m-1] = 5

print('A \n', A)

#---- build diagonal square array without loop
B = np.zeros((m, m))

B[0, 0] = 0.1
B[0, 1] = 0.2

np.fill_diagonal(B, [1, 2, 3])

B[m-1, m-2] = 4
B[m-1, m-1] = 5

print('B \n', B)

那么有没有办法构建像矩阵A所示的对角矩阵而不使用for循环?

2 个答案:

答案 0 :(得分:4)

scipy.sparse中有这样的功能,例如:

from scipy.sparse import diags

C = diags([1,2,3], [-1,0,1], shape=(5,5), dtype=float)

C = C.toarray()

C[0, 0] = 0.1
C[0, 1] = 0.2
C[-1, -2] = 4
C[-1, -1] = 5

对角矩阵通常非常稀疏,因此您也可以将其保持为稀疏矩阵。根据应用的不同,这甚至可以带来很大的效率优势。


稀疏矩阵的效率增益可能会让您非常依赖矩阵大小。对于5x5阵列,我猜你真的很烦恼。但对于较大的矩阵,使用稀疏矩阵创建数组可以快得多,下面的示例用一个单位矩阵说明:

%timeit np.eye(3000)
# 100 loops, best of 3: 3.12 ms per loop

%timeit sparse.eye(3000)
# 10000 loops, best of 3: 79.5 µs per loop

但是当你需要对稀疏的数组进行数学运算时,会显示稀疏矩阵数据类型的真正强度:

%timeit np.eye(3000).dot(np.eye(3000))
# 1 loops, best of 3: 2.8 s per loop

%timeit sparse.eye(3000).dot(sparse.eye(3000))
# 1000 loops, best of 3: 1.11 ms per loop

或者当你需要使用一些非常大但稀疏的数组时:

np.eye(1E6)
# ValueError: array is too big.

sparse.eye(1E6)
# <1000000x1000000 sparse matrix of type '<type 'numpy.float64'>'
# with 1000000 stored elements (1 diagonals) in DIAgonal format>

答案 1 :(得分:0)

请注意,0的数量始终为3(或者,如果您想要像这样的对角矩阵,则为常量):

In [10]:    
import numpy as np
A1=[0.1, 0.2]
A2=[1,2,3]
A3=[4,5]
SPC=[0,0,0] #=or use np.zeros #spacing zeros
np.hstack((A1,SPC,A2,SPC,A2,SPC,A2,SPC,A3)).reshape(5,5)
Out[10]:
array([[ 0.1,  0.2,  0. ,  0. ,  0. ],
       [ 1. ,  2. ,  3. ,  0. ,  0. ],
       [ 0. ,  1. ,  2. ,  3. ,  0. ],
       [ 0. ,  0. ,  1. ,  2. ,  3. ],
       [ 0. ,  0. ,  0. ,  4. ,  5. ]])

In [11]:    
import itertools #A more general way of doing it
np.hstack(list(itertools.chain(*[(item, SPC) for item in [A1, A2, A2, A2, A3]]))[:-1]).reshape(5,5)
Out[11]:
array([[ 0.1,  0.2,  0. ,  0. ,  0. ],
       [ 1. ,  2. ,  3. ,  0. ,  0. ],
       [ 0. ,  1. ,  2. ,  3. ,  0. ],
       [ 0. ,  0. ,  1. ,  2. ,  3. ],
       [ 0. ,  0. ,  0. ,  4. ,  5. ]])