如何在N张量(ndarray)中选择我选择的2个指数

时间:2017-02-11 00:25:37

标签: python numpy

我有一个2 ^ L x 2 ^ L矩阵,然后通过重塑命令将其转换为等级2L的张量,每个轴具有2个元素。例如,对于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索引。但它会使指数秩序陷入混乱,因此进一步的收缩将非常困难,所以我真的在努力应对如何实现这种收缩。

2 个答案:

答案 0 :(得分:2)

在一个或多个轴上求和

这是一个疯狂的猜测,你的意思是'收缩' - sum沿一个或两个轴。

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]])

einsum trace

要更多地探索@Paul Panzer's跟踪答案,可以使用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如何运作,reshape路线更容易:

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)

上的跟踪
In [426]: a2 = a1.reshape(dex)
In [427]: a2.shape
Out[427]: (1, 2, 2, 1)
In [429]: np.einsum('ijjk',a2)
Out[429]: array([[30]])

两条痕迹都可以在一个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

答案 1 :(得分:2)

我假设你指的是"广义跟踪"意义上的张量收缩,所以让我们看看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]]]])

最后,你可以squeeze多余的轴。

>>> np.squeeze(_)
array([[ 9, 13],
       [17, 21]])