使用python / numpy,我可以创建3D数组(注意矩阵指数函数)我想这样
import numpy as np
from scipy.linalg import expm
a = np.arange(3)
B = np.ones((2,2))
C = np.zeros((2,2,3))
for i in range(3):
C[:,:,i] = expm(a[i]*B)
产生C,即3D阵列
[[[ 1. 4.19452805 27.79907502]
[ 0. 3.19452805 26.79907502]]
[[ 0. 3.19452805 26.79907502]
[ 1. 4.19452805 27.79907502]]]
但我想消除循环。有什么办法可以摆脱for
循环吗?也许是通过NumPy广播?我曾想过np.kron
,但似乎无法找到一个好的方法来重塑,以便我可以应用expm
函数,这需要一个正方形数组作为参数。
答案 0 :(得分:1)
使用Sylvester's Formula和稍微不同的形状,您可以执行此向量化操作:
C = a[:, None, None] * B
C.shape
(3, 2, 2)
E, V = np.linalg.eig(C)
V.swapaxes(-1,-2) @ np.exp(E)[..., None] * V
array([[[ 1. , 0. ],
[ 0. , 1. ]],
[[ 4.19452805, -4.19452805],
[ -3.19452805, -3.19452805]],
[[ 27.79907502, -27.79907502],
[-26.79907502, -26.79907502]]])
此方法可以将任意数量的方形矩阵作为(*, N, N)
数组中的输入,但是当它消除了for
循环开销时,它会将其交换为np.linalg.eig
调用,这可能是如果N
很大,则会缓慢。
答案 1 :(得分:0)
我不确定这是否与您所希望的完全相同,但如果没有for循环,它会给出相同的结果。
a = np.arange(3)
B = np.ones((2,2))
C = np.array([expm(a[i]*B) for i in range(3)]).T
在那里,仍然是" for"在列表理解中,不确定这是否符合您的目的。
答案 2 :(得分:0)
如果你想在for循环中多次调用expm
来获得结果,你可以像这样构造输入:
import numpy as np
from scipy.linalg import expm
n = 4
t = np.zeros([n*2, n*2])
for i in range(n):
t[2*i:2*i+2, 2*i:2*i+2] = i
C0 = expm(t)
这会产生格式
>>> t
array([[0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 1., 1., 0., 0., 0., 0.],
[0., 0., 1., 1., 0., 0., 0., 0.],
[0., 0., 0., 0., 2., 2., 0., 0.],
[0., 0., 0., 0., 2., 2., 0., 0.],
[0., 0., 0., 0., 0., 0., 3., 3.],
[0., 0., 0., 0., 0., 0., 3., 3.]])
>>> C0
array([[ 1. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. ],
[ 0. , 1. , 0. , 0. ,
0. , 0. , 0. , 0. ],
[ 0. , 0. , 4.19452805, 3.19452805,
0. , 0. , 0. , 0. ],
[ 0. , 0. , 3.19452805, 4.19452805,
0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ,
27.79907502, 26.79907502, 0. , 0. ],
[ 0. , 0. , 0. , 0. ,
26.79907502, 27.79907502, 0. , 0. ],
[ 0. , 0. , 0. , 0. ,
0. , 0. , 202.21439675, 201.21439675],
[ 0. , 0. , 0. , 0. ,
0. , 0. , 201.21439675, 202.21439675]])
如果您坚持在C
的示例结构中使用结果,我相信您必须使用某种循环(列表理解,range
或其他方式)来实现此目的,因为我不认为这是这种功能的标准输出结构。
i1 = range(0, 2*n, 2)
i2 = range(1, 2*n+1, 2)
i = (tuple(i1 + i2 + i1 + i2), tuple(i1 + i1 + i2 + i2))
C = C0[i].reshape(2,2,n)
>>> C
array([[[ 1. , 4.19452805, 27.79907502, 202.21439675],
[ 0. , 3.19452805, 26.79907502, 201.21439675]],
[[ 0. , 3.19452805, 26.79907502, 201.21439675],
[ 1. , 4.19452805, 27.79907502, 202.21439675]]])
对于较大的输入,expm
处理稀疏的方阵,因此您不应该对内存有任何问题。