让我们举一个简单的例子,我有数据数组
A = np.asarray([[1,3], [2,4]])
此数据将在简单转换后转换为另一种形式:
Q = np.asarray([[-0.5,1], [1,0.5]])
B = np.dot(Q,np.dot(A,Q.T))
print B
现在假设我有一组数据,它采用2d数组的形式,用于几个时间步。为简单起见,再次假设此数据仅复制A
3个时间步。我们可以将此数据表示为维度为(2,2,N)
的3d数组,在这种情况下为N =3
。然后,第三个维度表示数据的时间索引。现在要求有一种简单的方法来转换数据如上所述,但是对于每个时间步骤,通过3d数组的直观乘法,我只能做出以下不直观的工作:< / p>
# Create the 3d data array
AA = np.tile(A,(3,1,1)) # shape (3,2,2)
BB = np.dot(Q,np.dot(AA,Q.T))
print np.all( BB[:,0,:] == B ) # Returns true
因此,使用这种方法,我不必重新设定Q
数组以使其正常工作,但现在第二个维度将作为&#34; time&#34;索引有点反直觉,因为在AA
它是表示时间的第一个维度...理想情况下我想要一个AA
和BB
都有时间索引的解决方案在第三维度!
编辑:
从文档dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])
开始,我想知道我想要实现的是不可能的?这似乎很奇怪,因为这应该是一个人们可能想要的相对普遍的事情......
答案 0 :(得分:1)
In [91]: A=np.array([[1,3],[2,4]])
In [92]: Q=np.array([[-.5,1],[1,.5]])
In [93]: B=np.dot(Q,np.dot(A,Q.T))
In [94]: B
Out[94]:
array([[ 1.75, 2.75],
[ 4. , 4.5 ]])
与einsum
相同的计算:
In [95]: np.einsum('ij,jk,kl',Q,A,Q)
Out[95]:
array([[ 1.75, 2.75],
[ 4. , 4.5 ]])
如果我在新的第一维上制作了A
的多个副本:
In [96]: AA = np.array([A,A,A])
In [97]: AA.shape
Out[97]: (3, 2, 2)
...
In [99]: BB=np.einsum('ij,pjk,kl->pil',Q,AA,Q)
In [100]: BB
Out[100]:
array([[[ 1.75, 2.75],
[ 4. , 4.5 ]],
[[ 1.75, 2.75],
[ 4. , 4.5 ]],
[[ 1.75, 2.75],
[ 4. , 4.5 ]]])
BB
有一个(3,2,2)形状。
新的matmul
(@运算符)让我做同样的事情
In [102]: Q@A@Q.T
Out[102]:
array([[ 1.75, 2.75],
[ 4. , 4.5 ]])
In [103]: Q@AA@Q.T
Out[103]:
array([[[ 1.75, 2.75],
[ 4. , 4.5 ]],
[[ 1.75, 2.75],
[ 4. , 4.5 ]],
[[ 1.75, 2.75],
[ 4. , 4.5 ]]])
使用einsum
,使用最后一个维度同样容易:
In [104]: AA3=np.stack([A,A,A],-1) # newish np.stack
In [105]: AA3.shape
Out[105]: (2, 2, 3)
In [106]: np.einsum('ij,jkp,kl->ilp',Q,AA3,Q)
Out[106]:
array([[[ 1.75, 1.75, 1.75],
[ 2.75, 2.75, 2.75]],
[[ 4. , 4. , 4. ],
[ 4.5 , 4.5 , 4.5 ]]])
In [107]: _.shape
Out[107]: (2, 2, 3)
答案 1 :(得分:0)
我不确定我同意你对#34;直觉&#34;的定义 - 对我而言,通过数组的第一维表示时间索引似乎更自然。由于numpy数组默认为row-major,因此对于每个2x2子矩阵,维度的这种排序将为您提供更好的locality of reference,因为所有元素都位于相邻的内存地址中。
尽管如此,通过使用np.matmul
并转置每个中间数组,可以使您的示例适用于(2, 2, N)
数组:
CC = np.repeat(A[..., None], 3, -1) # shape (2, 2, 3)
DD = np.matmul(Q.T, np.matmul(CC.T, Q)).T
print(DD.shape)
# (2, 2, 3)
print(repr(DD))
# array([[[ 1.75, 1.75, 1.75],
# [ 2.75, 2.75, 2.75]],
# [[ 4. , 4. , 4. ],
# [ 4.5 , 4.5 , 4.5 ]]])
在Python 3.5+中,您可以使用@
operator作为np.matmul
的简写,使其更加紧凑:
DD = (Q.T @ (CC.T @ Q)).T