1、np.nditer():numpy迭代器
默認情況下,nditer
將視待迭代遍歷的數組為只讀對象(read-only),為了在遍歷數組的同時,實現對數組元素值得修改,必須指定op_flags=['readwrite']模式:
np.nditer(a, op_flags=['readwrite'])
基本迭代參數flag=['f_index'/'mulit_index'],可輸出自身坐標it.index/it.multi_index:
a = np.arange(6).reshape(2,3) '''迭代方式''' # 單維迭代 it = np.nditer(a, flags=['f_index']) while not it.finished: print("%d <%s>" % (it[0], it.index)) it.iternext() #0 <0> #1 <2> #2 <4> #3 <1> #4 <3> #5 <5> # 多維迭代 it = np.nditer(a, flags=['multi_index']) while not it.finished: print("%d <%s>" % (it[0], it.multi_index)) it.iternext() #0 <(0, 0)> #1 <(0, 1)> #2 <(0, 2)> #3 <(1, 0)> #4 <(1, 1)> #5 <(1, 2)>
改變迭代的順序:
# 列順序迭代 it = np.nditer(a, flags=['f_index'], order='F') while not it.finished: print("%d <%s>" % (it[0], it.index), end=' | ') it.iternext() # 0 <0> | 3 <1> | 1 <2> | 4 <3> | 2 <4> | 5 <5> | # 行順序迭代 it = np.nditer(a, flags=['f_index'], order='C') while not it.finished: print("%d <%s>" % (it[0], it.index), end=' | ') it.iternext() # 0 <0> | 1 <2> | 2 <4> | 3 <1> | 4 <3> | 5 <5> |
2、ufunc運算
ufunc是universal function的縮寫,它是一種能對數組的每個元素進行操作的函數。NumPy內置的許多ufunc函數都是在C語言級別實現的,因此它們的計算速度非常快。
通過組合標准的ufunc函數的調用,可以實現各種算式的數組計算。不過有些時候這種算式不易編寫,而針對每個元素的計算函數卻很容易用Python實現,這時可以用frompyfunc函數將一個計算單個元素的函數轉換成ufunc函數。這樣就可以方便地用所產生的ufunc函數對數組進行計算了。讓我們來看一個例子。
我們想用一個分段函數描述三角波,三角波的樣子如下圖所示:

三角波可以用分段函數進行計算
我們很容易根據上圖所示寫出如下的計算三角波某點y坐標的函數:
def triangle_wave(x, c, c0, hc): x = x - int(x) # 三角波的周期為1,因此只取x坐標的小數部分進行計算 if x >= c: r = 0.0 elif x < c0: r = x / c0 * hc else: r = (c-x) / (c-c0) * hc return r
顯然triangle_wave函數只能計算單個數值,不能對數組直接進行處理。我們可以用下面的方法先使用列表包容(List comprehension),計算出一個list,然后用array函數將列表轉換為數組:
x = np.linspace(0, 2, 1000) y = np.array([triangle_wave(t, 0.6, 0.4, 1.0) for t in x])
這種做法每次都需要使用列表包容語法調用函數,對於多維數組是很麻煩的。讓我們來看看如何用frompyfunc函數來解決這個問題:
triangle_ufunc = np.frompyfunc( lambda x: triangle_wave(x, 0.6, 0.4, 1.0), 1, 1) y2 = triangle_ufunc(x)
frompyfunc的調用格式為frompyfunc(func, nin, nout),其中func是計算單個元素的函數,nin是此函數的輸入參數的個數,nout是此函數的返回值的個數。雖然triangle_wave函數有4個參數,但是由於后三個c, c0, hc在整個計算中值都是固定的,因此所產生的ufunc函數其實只有一個參數。為了滿足這個條件,我們用一個lambda函數對triangle_wave的參數進行一次包裝。這樣傳入frompyfunc的函數就只有一個參數了。這樣子做,效率並不是太高,另外還有一種方法:
def triangle_func(c, c0, hc): def trifunc(x): x = x - int(x) # 三角波的周期為1,因此只取x坐標的小數部分進行計算 if x >= c: r = 0.0 elif x < c0: r = x / c0 * hc else: r = (c-x) / (c-c0) * hc return r # 用trifunc函數創建一個ufunc函數,可以直接對數組進行計算, 不過通過此函數 # 計算得到的是一個Object數組,需要進行類型轉換 return np.frompyfunc(trifunc, 1, 1) y2 = triangle_func(0.6, 0.4, 1.0)(x)
我們通過函數triangle_func包裝三角波的三個參數,在其內部定義一個計算三角波的函數trifunc,trifunc函數在調用時會采用triangle_func的參數進行計算。最后triangle_func返回用frompyfunc轉換結果。
值得注意的是用frompyfunc得到的函數計算出的數組元素的類型為object,因為frompyfunc函數無法保證Python函數返回的數據類型都完全一致。因此還需要再次 y2.astype(np.float64)將其轉換為雙精度浮點數組。