Python學習(六)向量化


參考資料:

https://github.com/lijin-THU/notes-python(相應實體書為:《自學Python——編程基礎、科學計算及數據分析》)

1. 向量化函數

(1)自定義sinc函數

1 import numpy as np
2 
3 def sinc(x):
4     if x == 0.0:
5         return 1.0
6     else:
7         w = np.pi * x
8         return np.sin(w) / w

可以作用於單個數值:如sinc(0)、sinc(3.0);但是不能作用於數組x = np.array([1,2,3]);sinc(x) 報錯

(2)可以使用 numpy 的 vectorize 將函數 sinc 向量化,產生一個新的函數

1 x = np.array([1,2,3])
2 vsinc = np.vectorize(sinc)
3 vsinc(x)  #作用是為 x 中的每一個值調用 sinc 函數
1 import matplotlib.pyplot as plt
2 %matplotlib inline
3 
4 x = np.linspace(-5,5,101)
5 plt.plot(x, vsinc(x))

注:因為這樣的用法涉及大量的函數調用,因此,向量化函數的效率並不高

2. 二元運算

(1)四則運算

1 import numpy as np
2 a = np.array([1,2])
3 a * 3  #數組與標量相乘,相當於數組的每個元素乘以這個標量
4 
5 a = np.array([1,2])
6 b = np.array([3,4])
7 a * b  #數組相乘,結果為逐個元素對應相乘 8 np.multiply(a, b)  #使用函數
9 np.multiply(a, b, a)  #如果有第三個參數,表示將結果存入第三個參數中

(2)比較和邏輯運算  //大部分邏輯操作是逐個元素運算的,返回布爾數組

1 a = np.array([[1,2,3,4],
2               [2,3,4,5]])
3 b = np.array([[1,2,5,4],
4               [1,3,4,5]])
5 a == b  #等於操作是對應元素逐個進行比較的,返回的是等長的布爾數組

注:如果在條件中要判斷兩個數組是否一樣時,不能直接使用 if a==b: 需要使用 if all(a==b): 

對於浮點數,由於存在精度問題,使用函數 allclose 會更好 if allclose(a,b):

3. ufunc對象

(1)Numpy有兩種基本對象:ndarray (N-dimensional array object) 和 ufunc (universal function object)ndarray 是存儲單一數據類型的多維數組,而 ufunc 則是能夠對數組進行處理的函數。例如,我們之前所接觸到的二元操作符對應的 Numpy 函數,如 add,就是一種 ufunc 對象,它可以作用於數組的每個元素

1 import numpy as np
2 a = np.array([0,1,2])
3 b = np.array([2,3,4])
4 np.add(a, b)  #作用於每個元素,逐個元素相加,輸出array([2, 4, 6])

注:大部分能夠作用於數組的數學函數如三角函數等,都是 ufunc 對象

(2)可以查看ufunc對象支持的方法,如np.add對象:dir(np.add)

  • reduce方法:op.reduce(a)  將操作opp沿着某個軸應用,使得數組 a 的維數降低一維
1 a = np.array([1,2,3,4])
2 np.add.reduce(a)  #add 作用到一維數組上相當於求和(降低一維);輸出10
1 a = np.array([[1,2,3],[4,5,6]])
2 np.add.reduce(a)  #多維數組默認只按照第一維進行運算;輸出array([5, 7, 9])
3 np.add.reduce(a, 1)  #指定維度,輸出array([ 6, 15])
1 a = np.array(['ab', 'cd', 'ef'], np.object)
2 np.add.reduce(a)  #作用於字符串,輸出'abcdef'
3 
4 a = np.array([1,1,0,1])  
5 np.logical_and.reduce(a)  #邏輯與,輸出False
6 np.logical_or.reduce(a)  #邏輯或,輸出True
  •  accumulate方法op.accumulate(a):保存reduce方法每一步結果所形成的數組
1 a = np.array([1,2,3,4])
2 np.add.accumulate(a)  #array([1,3,6,10],dtype=int32)
3 
4 a = np.array(['ab', 'cd', 'ef'], np.object)
5 np.add.accumulate(a)  #array(['ab','abcd','abcdef'],dtype=object)
6 
7 a = np.array([1,1,0,1])
8 np.logical_and.accumulate(a)  #array([True, True, False, False])
9 np.logical_or.accumulate(a)  #array([True, True, True, True])
  • reduceat方法op.recuceat(a, indices):將操作符運用到指定的下標上,返回一個與indices大小相同的數組

1 a = np.array([0, 10, 20, 30, 40, 50])
2 indices = np.array([1,4])
3 np.add.reduceat(a, indices)  #輸出array([60, 90])
#60為從下標1(包括)到下標4(不包括)的運算結果;90位下標4(包括)到結尾的操作結果
  • outer方法op.outer(a,b):對於 a 中每個元素,將 op 運用到它和 b 的每一個元素上所得到的結果(結果大小為a.size*b.size)
1 a = np.array([0,1])
2 b = np.array([1,2,3])
3 #操作順序有區別
4 np.add.outer(a, b)  #array([[1,2,3],[2,3,4]])
5 np.add.outer(b, a)  #array([[1,2],[2,3],[3,4]])

4. choose函數實現條件篩選(類似switch和case操作)

1 import numpy as np
2 control = np.array([[1,0,1],
3                     [2,1,0],
4                     [1,2,2]])
5 #control控制元素的對應下標,將下標0、1、2的值分別映射為10,11,12
6 np.choose(control, [10, 11, 12])
#結果和control大小相同,為
array([[11, 10, 11],
       [12, 11, 10],
       [11, 12, 12]])
 1 i0 = np.array([[0,1,2],
 2                [3,4,5],
 3                [6,7,8]])
 4 i2 = np.array([[20,21,22],
 5                [23,24,25],
 6                [26,27,28]])
 7 control = np.array([[1,0,1],
 8                     [2,1,0],
 9                     [1,2,2]])
10 #根據choose中對應下標所在位置,映射為下標對應的數組的相應位置
11 np.choose(control, [i0, 10, i2])  #0對應i0,1對應10,2對應i2
輸出:array([[10,  1, 10],
         [23, 10,  5],
         [10, 27, 28]])
#將數組中所有小於10的值變為10
1
a = np.array([[ 0, 1, 2], 2 [10,11,12], 3 [20,21,22]]) 4 np.choose(a < 10, (a, 10))  #True=1對應於10,False=0對應於數組a(選取相應位置的值
1 a = np.array([[ 0, 1, 2], 
2               [10,11,12], 
3               [20,21,22]])
4 
5 lt = a < 10
6 gt = a > 15
7 #將數組中所有小於 10 的值變成了 10,大於 15 的值變成了 15
8 choice = lt + 2 * gt  #0對應a,1對應10,2對應15
9 np.choose(choice, (a, 10, 15))

5. 數組廣播機制

 1 import numpy as np
 2 a = np.array([[ 0, 0, 0],
 3               [10,10,10],
 4               [20,20,20],
 5               [30,30,30]])
 6 b = np.array([[ 0, 1, 2],
 7               [ 0, 1, 2],
 8               [ 0, 1, 2],
 9               [ 0, 1, 2]])
10 a + b  #正常加法
11 
12 b = np.array([0,1,2])  #b為一維數組array([0,1,2])shape為(3,) 13 a + b  #將b擴展為先前的數組形狀 14 
15 a = np.array([0,10,20,30])  #此時a.shape為(4,),a+b會由於維度不匹配報錯
ValueError: operands could not be broadcast together with shapes (4,) (3,) 
16 a.shape = 4,1  #等價於a= a[:, np.newaxis],a為一維列向量array([[0],[10],[20],[30]]),shape為(4,1)
17 a+b  #二者均自動擴展為最初數組形狀

對於 Numpy 來說,維度匹配當且僅當:

  • 維度相同
  • 有一個的維度是1

匹配會從最后一維開始進行,直到某一個的維度全部匹配為止

1 x = np.linspace(-.5,.5, 21)  #(21,) 2 y = x[:, np.newaxis]  #(21,1) 3 radius = np.sqrt(x ** 2 + y ** 2)  #因為y存在一維,所以自動擴展x、y為21*21 4 import matplotlib.pyplot as plt
5 %matplotlib inline
6 
7 plt.imshow(radius)

 


免責聲明!

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



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