通常,np.vectorize用于将标量(Python非numpy)函数应用于数组的所有元素或数组。还有那往往忽略了一个注:主要是为了方便而提供
的vectorize功能,而不是 性能。实现本质上是一个for循环。
In [278]: m = np.array([[1,2,3],[4,5,6]])
In [279]: np.vectorize(lambda x:2*x)(m)
Out[279]:
array([[ 2, 4, 6],
[ 8, 10, 12]])
这乘以2的m每个元素,照顾循环纸工作的我们。
更好的是,当给定几个数组时,它会广播('外部产品'的泛化)。
In [280]: np.vectorize(lambda x,y:2*x+y)(np.arange(3), np.arange(2)[:,None])
Out[280]:
array([[0, 2, 4],
[1, 3, 5]])
这馈送(x,y)标量元组拉姆达用于广播的针对(2,1)阵列(3)阵列的所有组合,产生了(2,3)阵列。它可以被看作是广播的map的扩展。
np.vectorize(np.rot90)的问题是rot90需要一个2d数组,但是vectorize将为其提供标量。
但是我在文档中看到,对于v1.12他们已经添加了签名参数。这是我第一次使用它。
你的问题 - 应用np.rot90到三维数组的2D元素:
In [266]: m = np.array([[1,2,3],[4,5,6]])
In [267]: a = np.stack([m,m])
In [268]: a
Out[268]:
array([[[1, 2, 3],
[4, 5, 6]],
[[1, 2, 3],
[4, 5, 6]]])
虽然你可以描述这个a为二维数组的数组,最好是把它当作一个整数三维阵列。这就是np.vectorize(myfun)(a)看到它,给每个号码myfun。
应用到2D m:
In [269]: np.rot90(m)
Out[269]:
array([[3, 6],
[2, 5],
[1, 4]])
使用Python工作的马,在列表理解:
In [270]: [np.rot90(i) for i in a]
Out[270]:
[array([[3, 6],
[2, 5],
[1, 4]]), array([[3, 6],
[2, 5],
[1, 4]])]
结果是一个列表,但我们可以换,在np.array。
Python map做同样的事情。
In [271]: list(map(np.rot90, a))
Out[271]:
[array([[3, 6],
[2, 5],
[1, 4]]), array([[3, 6],
[2, 5],
[1, 4]])]
理解和映射都在结果2d元素上的a,action的第1维上迭代。
vectorizesignature用:
In [272]: f = np.vectorize(np.rot90, signature='(n,m)->(k,l)')
In [273]: f(a)
Out[273]:
array([[[3, 6],
[2, 5],
[1, 4]],
[[3, 6],
[2, 5],
[1, 4]]])
的signature告诉它传递一个二维数组,并期望背面的2D阵列。 (我应该探讨如何signature扮演与otypes参数。)
一些快速的时间比较:
In [287]: timeit np.array([np.rot90(i) for i in a])
10000 loops, best of 3: 40 µs per loop
In [288]: timeit np.array(list(map(np.rot90, a)))
10000 loops, best of 3: 41.1 µs per loop
In [289]: timeit np.vectorize(np.rot90, signature='(n,m)->(k,l)')(a)
1000 loops, best of 3: 234 µs per loop
In [290]: %%timeit f=np.vectorize(np.rot90, signature='(n,m)->(k,l)')
...: f(a)
...:
1000 loops, best of 3: 196 µs per loop
因此,对于一小阵,Python的list方法更快,通过颇有几分。有时候,numpy方法对于更大的阵列会更好,尽管我在这种情况下怀疑。
rot90与轴的参数,甚至更好,而且会具有较大的阵列做的很好:
In [292]: timeit np.rot90(a,axes=(1,2))
100000 loops, best of 3: 15.7 µs per loop
望着np.rot90代码,我看到,它只是做np.flip(反向)和np.transpose,在各种组合取决于k。在这种情况下,效果是这样做的:
In [295]: a.transpose(0,2,1)[:,::-1,:]
Out[295]:
array([[[3, 6],
[2, 5],
[1, 4]],
[[3, 6],
[2, 5],
[1, 4]]])
(这是速度甚至比rot90)
我怀疑vectorize与signature正在做这样的事情:
In [301]: b = np.zeros(2,dtype=object)
In [302]: b[...] = [m,m]
In [303]: f = np.frompyfunc(np.rot90, 1,1)
In [304]: f(b)
Out[304]:
array([array([[3, 6],
[2, 5],
[1, 4]]),
array([[3, 6],
[2, 5],
[1, 4]])], dtype=object)
np.stack(f(b))会将对象数组转换为像其他代码一样的3d数组。
frompyfunc是vectorize的基础函数,并返回一个对象数组。在这里我创建一个像你的a这样的数组,除了它是1d,包含多个m数组。它是一个数组数组,而不是一个3d数组。