Python 如何在秩N张量(ndarray)中选择收缩2个索引
我有一个2^L x 2^L矩阵,然后通过每个轴有2个元素的重塑命令将其转换为秩为2L的张量。例如,对于L=2,它将是:Python 如何在秩N张量(ndarray)中选择收缩2个索引,python,numpy,Python,Numpy,我有一个2^L x 2^L矩阵,然后通过每个轴有2个元素的重塑命令将其转换为秩为2L的张量。例如,对于L=2,它将是: Z = np.asarray([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]]) X = np.reshape(Z,[2,2,2,2]) 我曾尝试使用np.einsum通过交换轴对L和2L指数求和。但这会打乱指数的顺序,因此进一步收缩将非常困难,因此我真的很想知道如何执行这种收缩。在一个或多个轴上求和 关于你所说的“收缩”——
Z = np.asarray([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])
X = np.reshape(Z,[2,2,2,2])
我曾尝试使用np.einsum
通过交换轴对L和2L指数求和。但这会打乱指数的顺序,因此进一步收缩将非常困难,因此我真的很想知道如何执行这种收缩。在一个或多个轴上求和
关于你所说的“收缩”——沿着一个或两个轴的总和,这里有一个粗略的猜测
In [239]: X.sum(1)
Out[239]:
array([[[ 6, 8],
[10, 12]],
[[22, 24],
[26, 28]]])
In [240]: np.einsum('ijkl->ikl',X)
Out[240]:
array([[[ 6, 8],
[10, 12]],
[[22, 24],
[26, 28]]])
In [241]: np.einsum('ijkl->il',X)
Out[241]:
array([[16, 20],
[48, 52]])
In [242]: X.sum((1,2))
Out[242]:
array([[16, 20],
[48, 52]])
In [243]: X.sum(2).sum(1)
Out[243]:
array([[16, 20],
[48, 52]])
艾因苏姆痕迹
要进一步探索@Paul Panzer的
跟踪答案,可以使用einsum
计算(0,3)跟踪,如下所示:
In [314]: a1=np.einsum('ijki', a) # repeated indicies
In [315]: a1
Out[315]:
array([[ 9, 13],
[17, 21]])
In [316]: a1[None,:,:,None] # restore the dimensions
Out[316]:
array([[[[ 9],
[13]],
[[17],
[21]]]])
从i,j=0,3
以编程方式执行此操作需要更多的工作。构建备选einsum
语法可能是最容易的
a1=np.einsum(a, [0,1,2,0])
In [321]: dex=np.arange(a.ndim)
In [322]: dex[j]=dex[i]
In [323]: dex
Out[323]: array([0, 1, 2, 0])
In [324]: a1=np.einsum(a, dex.tolist())
In [325]: a1
Out[325]:
array([[ 9, 13],
[17, 21]])
newaxis
扩展可以从切片和None
构建:
In [326]: dex=np.zeros(a.ndim, object)
In [327]: dex[...]=slice(None)
In [328]: dex[[i,j]] = None
In [329]: dex
Out[329]: array([None, slice(None, None, None), slice(None, None, None), None], dtype=object)
In [330]: a1[tuple(dex)]
Out[330]:
array([[[[ 9],
[13]],
[[17],
[21]]]])
但是看看expand_dims
的工作原理,重塑
路线更容易:
In [334]: dex = np.array(a.shape)
In [335]: dex[[i,j]]=1
In [336]: dex
Out[336]: array([1, 2, 2, 1])
In [337]: a1.reshape(dex)
双重收缩
你提到了进一步的收缩操作。在这种4d情况下,我假设这意味着在轴(1,2)上跟踪跟踪
两条记录道都可以在一个einsum
中进行:
In [430]: np.einsum('ijji',a)
Out[430]: 30
In [431]: np.trace(a1)
Out[431]: 30
时间安排
einsum
趋向于与dot
一样好,尽管当数组变得非常大时,它会变松,并且它的迭代空间会增加。但在这里,它始终比双重跟踪做得更好:
In [464]: N=100;abig=np.arange(N*N*N*N).reshape(N,N,N,N)
In [465]: abig.shape
Out[465]: (100, 100, 100, 100)
In [466]: timeit np.trace(np.trace(abig,0,0,3))
100 loops, best of 3: 12.4 ms per loop
In [467]: timeit np.einsum('ijji',abig)
The slowest run took 7.51 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 30.2 µs per loop
我假设你指的是“广义轨迹”意义上的张量收缩,那么让我们看看
numpy.trace
能为我们做些什么:
>>> import numpy as np
>>> a = np.arange(16).reshape(2, 2, 2, 2)
>>> L, i, j = 2, 0, 1
>>> np.trace(a, axis1=i, axis2=L+j)
array([[ 9, 13],
[17, 21]])
如果必须多次执行此操作并且不希望轴移动,只需插入新轴以替换收缩的轴即可
>>> np.expand_dims(np.expand_dims(_, i), L+j)
array([[[[ 9],
[13]],
[[17],
[21]]]])
最后,您可以挤压
多余的轴
>>> np.squeeze(_)
array([[ 9, 13],
[17, 21]])
你想要的具体操作是什么?您能为
L=1
显示吗<代码>[[1,2],[3,4]]->?你所说的收缩是什么意思?它不是numpy
中的常用术语。你想沿着其中一个轴做加法吗?收缩意味着在数据列中求两个轴的和。np.trace可以像保罗在下面说的那样做汉克斯!多余轴上的注释对于(0,3)跟踪,np.einsum('[ijki',a)
或np.einsum(a[0,1,2,0])非常有用
works@hpaulj我真的应该学习一下einsum magic!它比现有的专用函数有什么优势吗?我想我读到过einsum过去比numpy内置函数更快的地方。仍然是这样吗?同样,有什么理由不使用expand\u dims
和其他类似moveaxis
的便利吗当轴和尺寸不固定时,它们会使生活变得更加轻松。
>>> np.squeeze(_)
array([[ 9, 13],
[17, 21]])