[英]Using numpy.vectorize() to rotate all elements of a NumPy array
我正處於學習NumPy的開始階段。 我有一個3x3矩陣的Numpy數組。 我想創建一個新的數組,其中每個矩陣旋轉90度。 我已經研究了這個答案,但我仍然無法弄清楚我做錯了什么。
import numpy as np
# 3x3
m = np.array([[1,2,3], [4,5,6], [7,8,9]])
# array of 3x3
a = np.array([m,m,m,m])
# rotate a single matrix counter-clockwise
def rotate90(x):
return np.rot90(x)
# function that can be called on all elements of an np.array
# Note: I've tried different values for otypes= without success
f = np.vectorize(rotate90)
result = f(a)
# ValueError: Axes=(0, 1) out of range for array of ndim=0.
# The error occurs in NumPy's rot90() function.
注意:我意識到我可以執行以下操作,但我想了解矢量化選項。
t = np.array([ np.rot90(x, k=-1) for x in a])
無需單獨進行旋轉: numpy
具有內置numpy.rot90(m, k=1, axes=(0, 1))
函數。 默認情況下,矩陣在第一維和第二維上旋轉。
如果你想要更深一級旋轉,你只需設置旋轉發生的軸,更深一層(如果你想在不同的方向旋轉,可選擇交換它們)。 或者如文檔所述:
axes: (2,) array_like
陣列在由軸定義的平面中旋轉。 軸必須不同。
所以我們在y和z平面上旋轉(如果我們標注尺寸x , y和z ),那么我們指定(2,1)
或(1,2)
。
當您想要向右/向左旋轉時,您所要做的就是正確設置axes
:
np.rot90(a,axes=(2,1)) # right
np.rot90(a,axes=(1,2)) # left
這將旋轉所有矩陣,如:
>>> np.rot90(a,axes=(2,1))
array([[[7, 4, 1],
[8, 5, 2],
[9, 6, 3]],
[[7, 4, 1],
[8, 5, 2],
[9, 6, 3]],
[[7, 4, 1],
[8, 5, 2],
[9, 6, 3]],
[[7, 4, 1],
[8, 5, 2],
[9, 6, 3]]])
或者如果你想向左旋轉 :
>>> np.rot90(a,axes=(1,2))
array([[[3, 6, 9],
[2, 5, 8],
[1, 4, 7]],
[[3, 6, 9],
[2, 5, 8],
[1, 4, 7]],
[[3, 6, 9],
[2, 5, 8],
[1, 4, 7]],
[[3, 6, 9],
[2, 5, 8],
[1, 4, 7]]])
請注意,您只能從numpy 1.12和(可能)未來版本中指定axes
。
通常, 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]])
這將m
的每個元素乘以2,為我們處理循環的文書工作。
更好的是,當給出幾個陣列時,它會廣播(“外部產品”的概括)。
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]])
對於(2,1)數組廣播的(3,)數組的所有組合,這將(x,y)
標量元組提供給lambda,得到(2,3)數組。 它可以被視為map
的廣播擴展。
np.vectorize(np.rot90)
的問題是rot90
需要一個2d數組,但是vectorize
會為它提供標量。
但是我在文檔中看到,對於v1.12
他們添加了一個簽名參數。 這是我第一次使用它。
您的問題 - 將np.rot90
應用於3d數組的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
為二維數組的數組,最好是把它當作一個整數3D陣列。 這就是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]])]
理解和映射都在a的第一維上迭代,對結果的2d元素進行動作。
使用signature
vectorize
:
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數組並期望返回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列表方法更快,相當多。 有時,對於較大的陣列, numpy
方法會做得更好,但我懷疑在這種情況下。
使用axes參數的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
更快。)
我懷疑帶有signature
vectorize
是這樣的:
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數組。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.