给定1D指数数组的3D阵列矢量化二维阵列

时间:2017-03-14 18:27:02

标签: python arrays numpy vectorization

给定一个数组 x ,形状(2,n,m)和一组索引 [i,j] 其中 i,j< n ,我试图获得一个形状(2,m)的数组,其中第一个数组位于索引 [0,i] 和第二个数组在索引 [1,j] 。这是用于推广到形状(b,n,m)的数组和一组长度为 b 的索引的测试用例。

此操作的明显选择是 np.choose ,但这与预期的行为不同。我们希望将第一个数组的行 i 与第二个数组的行 j 配对。但是,当使用 np.choose([i,j],x)时, np.choose 会对中的第一个进行配对数组索引为 i ,其中第二列来自数组,索引为 j (可在下面的代码中看到)得到一个形状(n,m)的数组。显然这个任务很容易用for循环执行,但由于用例(在Keras中作为张量的自定义函数,禁止迭代)我不能这样做。是否有使用Keras后端函数或Numpy执行此操作的矢量化方法?我目前正在使用" map"要做到这一点,如果我弄明白,我会用自己的答案进行更新。

这是一段代码片段,向您展示np.choose如何处理(2,n,m)数组:

>>> import numpy as np 
>>> x = np.random.rand(2,4,2)
>>> choices = [3,1]
>>> np.choose(choices,x)
    ValueError: invalid entry in choice array
>>> np.choose([0,0],x)
    #Returns an array with x[0,:,0] and x[0,:,1] in shape(4,2)

1 个答案:

答案 0 :(得分:1)

我相信你可以使用advanced indexing。举个例子:

import numpy as np 
x = np.random.randint(0,10,(2,4,3))

x是:

[[[0 4 1]
  [8 8 1]
  [3 3 6]
  [4 7 8]]

 [[7 1 2]
  [5 9 9]
  [0 4 0]
  [7 8 3]]]

现在x[[0,1],[3,1],:]是:

[[4 7 8]
 [5 9 9]]

这可以扩展到(b,m,n)问题:

import numpy as np 
x = np.random.randint(0,10,(100,200,300))
choices= np.random.randint(0,200,(100))

def loop():
    res=np.empty((100,300),int)
    for i in range(100):
        res[i]=x[i,choices[i]]
    return res    

一些性能测试:

In [30]: %timeit loop()
10000 loops, best of 3: 140 µs per loop

In [31]: %timeit x[arange(100),choices,:]
10000 loops, best of 3: 23.7 µs per loop

这里的索引方法只比循环快6倍,因为任务 (提取)无法利用内存对齐。

最后,您可以通过loop2=numba.njit(loop)及时编译来增强循环。

In [32]: %timeit loop2()
10000 loops, best of 3: 32 µs per loop

表明索引方法是最优的。