『Numpy』高級函數_np.nditer()&ufunc運算


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函數對數組進行計算了。讓我們來看一個例子。

我們想用一個分段函數描述三角波,三角波的樣子如下圖所示:

_images/numpy_intro_01.png

三角波可以用分段函數進行計算

我們很容易根據上圖所示寫出如下的計算三角波某點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)將其轉換為雙精度浮點數組。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM