1. 程式人生 > >Numpy快速處理資料--ufunc運算(三)

Numpy快速處理資料--ufunc運算(三)

       ufunc是universal function的縮寫,它是一種能對陣列中每個元素進行操作的函式。Numpy內建的許多ufunc函式都是C語言實現的,計算速度非常快,簡單看個例子:

>>> x = np.linspace(0,2*np.pi,10)
>>> y=np.sin(x)
>>> y
array([  0.00000000e+00,   6.42787610e-01,   9.84807753e-01,
         8.66025404e-01,   3.42020143e-01,  -3.42020143e-01,
        -8.66025404e-01,  -9.84807753e-01,  -6.42787610e-01,
        -2.44929360e-16])
>>> 
      上述程式碼中先用linspace( )產生一個從0到2*PI的等差陣列,然後將其傳給np.sin( )計算每個元素的正弦值。函式計算完成後,返回一個計算結果的陣列。如果通過out引數指定計算結果的儲存位置,則計算結果將儲存在out引數中,如:
>>> np.sin(x, out =y)
array([  0.00000000e+00,   6.42787610e-01,   9.84807753e-01,
         8.66025404e-01,   3.42020143e-01,  -3.42020143e-01,
        -8.66025404e-01,  -9.84807753e-01,  -6.42787610e-01,
        -2.44929360e-16])
>>> y
array([  0.00000000e+00,   6.42787610e-01,   9.84807753e-01,
         8.66025404e-01,   3.42020143e-01,  -3.42020143e-01,
        -8.66025404e-01,  -9.84807753e-01,  -6.42787610e-01,
        -2.44929360e-16])
>>> 
       對於計算單個元素,則建議採用Math庫裡對應的函式,np.sin( )對應math.sin( ),因為對於np.sin( )為了實現陣列計算,底層做了很多複雜的處理,因此對於單個元素,math庫裡的函式計算速度快得多;而對於陣列元素,則採用numpy庫裡的函式計算
        在讀取計算結果時,通過下標獲取陣列元素的型別為Numpy中定義的型別,將其轉換為python的標準型別需耗時間。針對此問題,可以採用陣列提供的item( )方法,用來獲取陣列中單個元素,並直接返回標準的python資料型別,如:
>>> a = np.arange(6.0).reshape(2,3)
>>> a.item(1,2)  #與a[1,2]類似
5.0
>>> type(a.item(1,2))
<class 'float'>
>>> type(a[1,2])
<class 'numpy.float64'>
>>> 
         一、陣列的四則運算



           二、比較和布林運算

         使用“==”、“>”等比較運算子比較兩個陣列,將返回一個布林陣列,它的每個元素的值是兩個陣列對應元素比較的結果,如:

>>> np.array([1,2,3])==np.array([3,2,1])
array([False,  True, False], dtype=bool)
>>> np.array([1,2,3])<np.array([3,2,1])
array([ True, False, False], dtype=bool)
>>> 
       

 由於Python的布林運算使用and,or和Not等關鍵字,無法被過載,因此陣列的布林運算智慧通過ufunc對應的函式來操作,這些函式以"logical_"開頭,如下:


       以“bitwise_"開頭的函式是位元運算函式,包括bitwise_and、bitwise_not、bitwise_or和bitwise_xor等,也可以使用&、~、|、^等操作符來計算。對於布林陣列來說,位運算和布林運算的結果相同,但是位運算子的優先順序高於比較運算子。

        自定義ufunc函式

        通過Numpy提供的標準ufunc函式可以滿足大多要求,但有些特殊情況需要自定義函式來實現。這時,可以採用python來實現,然後使用frompyfunc( )函式將一個計算單個元素的函式轉換為ufunc函式。例如,用一個分段函式來描述三角波,它的樣子如圖所示:


Python函式定義如下:

def triangle_wave(x,c,c0,hc):
    x = x - int(x)   #週期為1,取小數部分計算
    if x>=c:
        r = 0.0
    elif x<c0:
        r = x/c0*hc
    else:
        r = (c-x)/(c-c0)*hc
    return r
          1)通過列表推導計算

         先使用列表推導計算一個列表,然後用array( )轉換為陣列,這種方法每次都要使用列表推導,而且對於多維陣列,比較複雜,計算如下:

x = np.linspace(0,2,1000)
y1 = np.array([triangle_wave(t,0.6,0.4,1.0) for t in x])
         2)fromnpyfunc( )函式計算

         通過frompyfunc( )可以將計算單個值的函式轉換為一個能對陣列中每個元素計算的ufunc函式。frompyfunc( )的呼叫格式為:

frompyfunc(func,nin,nout)
 其中,ufunc是計算單個元素的函式,nin是輸入引數的個數,nout是func返回值的個數。如:
triangle_wave_ufunc = np.frompyfunc(triangle_wave,4,1)
y2 = triangle_wave_ufunc(x,0.6,0.4,1.0)
程式碼簡潔高效。值得注意:triangle_wave_ufunc( )所返回陣列的元素型別是object,因此還需要呼叫陣列的astype()方法將其轉換為雙精度浮點陣列



           3)vectorize( )函式計算

        使用vectorize( )可以實現和frompyfunc( )類似的功能,但他可以通過otypes引數指定返回陣列的元素型別。otypes引數可以是一個表示元素型別的字串,也可以是一個型別列表,使用列表可以描述多個返回陣列的元素型別,如將上面的程式碼改成vectorize( ),則為:

triangle_wave_vec = np.vectorize(triangle_wave, otypes[np.float])
y3 = triangle_wave_vec(x,0.6,0.4,1.0)
       到這裡,ufunc函式的強大自不必言,如果將其與影象處理、訊號處理等陣列形式的應用結合起來,可以發揮強大作用。