NumPy基礎:矢量計算

通用函數:快速的元素級數組函數

通用函數(ufunc)是一種對ndarray中的數據執行元素級運算的函數。

可以把它看做簡單函數(接受一個或多個標量值,併產生一個或多個標量值)的矢量化包裝器。

sqrtexp

  1. import numpy as np
  2. arr = np.arange(10)
  3. arr
  4. # array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
  5. np.sqrt(arr)
  6. # array([ 0. , 1. , 1.41421356, 1.73205081, 2. ,
  7. # 2.23606798, 2.44948974, 2.64575131, 2.82842712, 3. ])
  8. np.exp(arr)
  9. # array([ 1.00000000e+00, 2.71828183e+00, 7.38905610e+00,
  10. # 2.00855369e+01, 5.45981500e+01, 1.48413159e+02,
  11. # 4.03428793e+02, 1.09663316e+03, 2.98095799e+03,
  12. # 8.10308393e+03])

這些是一元通用函數。也有接受2個數組的二元通用函數,並返回一個結果數組:

  1. x = np.random.randn(8)
  2. y = np.random.randn(8)
  3. x
  4. # array([ 0.18373557, -1.82728347, -0.11149882, -1.34286776, -1.09016986,
  5. # 1.63308 , 1.05205535, -0.32746706])
  6. y
  7. # array([-0.42410809, 1.89603273, -1.13649816, -0.98559379, -0.16827718,
  8. # 0.52828569, 1.57543351, 1.50045399])
  9. np.maximum(x, y)
  10. # array([ 0.18373557, 1.89603273, -0.11149882, -0.98559379, -0.16827718,
  11. # 1.63308 , 1.57543351, 1.50045399])

有些通用函數也可以返回多個數組。 modf就是一個例子,它是Python內置函數 divmod的矢量化版本。

一些一元通用函數:

一些二元通用函數:

利用數組進行數據處理

假設我們想要在一組值(網格型)上計算函數 sqrt(x^2+y^2)np.meshgrid函數接受兩個一維數組,併產生兩個二維矩陣(對應於兩個數組中所有的 (x,y)對):

  1. points = np.arange(-5, 5, 0.01)
  2. xs, ys = np.meshgrid(points, points)
  3. ys
  4. # array([[-5. , -5. , -5. , ..., -5. , -5. , -5. ],
  5. # [-4.99, -4.99, -4.99, ..., -4.99, -4.99, -4.99],
  6. # [-4.98, -4.98, -4.98, ..., -4.98, -4.98, -4.98],
  7. # ...,
  8. # [ 4.97, 4.97, 4.97, ..., 4.97, 4.97, 4.97],
  9. # [ 4.98, 4.98, 4.98, ..., 4.98, 4.98, 4.98],
  10. # [ 4.99, 4.99, 4.99, ..., 4.99, 4.99, 4.99]])
  11. z = np.sqrt(xs ** 2 + ys ** 2)
  12. z
  13. # array([[ 7.07106781, 7.06400028, 7.05693985, ..., 7.04988652,
  14. # 7.05693985, 7.06400028],
  15. # [ 7.06400028, 7.05692568, 7.04985815, ..., 7.04279774,
  16. # 7.04985815, 7.05692568],
  17. # [ 7.05693985, 7.04985815, 7.04278354, ..., 7.03571603,
  18. # 7.04278354, 7.04985815],
  19. # ...,
  20. # [ 7.04988652, 7.04279774, 7.03571603, ..., 7.0286414 ,
  21. # 7.03571603, 7.04279774],
  22. # [ 7.05693985, 7.04985815, 7.04278354, ..., 7.03571603,
  23. # 7.04278354, 7.04985815],
  24. # [ 7.06400028, 7.05692568, 7.04985815, ..., 7.04279774,
  25. # 7.04985815, 7.05692568]])

可以將函數值(一個二維數組)圖形化結果繪製出來:

  1. import matplotlib.pyplot as plt
  2. plt.imshow(z,cmap=plt.cm.gray);plt.colorbar()
  3. # <matplotlib.colorbar.Colorbar at 0x2415d064b70>
  4. plt.title("Image plot of $sqrt{x^2 + y^2}$ for a grid of values")
  5. # Text(0.5,1,Image plot of $sqrt{x^2 + y^2}$ for a grid of values)

將條件所及表述為數組運算

numpy.where函數是三元表達式 xifconditionelsey的矢量化版本。假如我們有:

  1. xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])
  2. yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])
  3. cond = np.array([True, False, True, True, False])

假設我們想要根據cond中的值選取xarr和yarr的值:當cond中的值為True時,選取xarr的值,否則從yarr中選取。列表推導式的寫法應該如下:

  1. result = [(x if c else y)
  2. for x, y, c in zip(xarr, yarr, cond)]
  3. result
  4. # [1.1000000000000001, 2.2000000000000002, 1.3, 1.3999999999999999, 2.5]

這有幾個問題:1.對大數組的處理速度不是很快,畢竟所有的工作都是由Python完成的。2.無法用於多維數組。使用 np.where可以將該功能寫得非常簡潔:

  1. result = np.where(cond, xarr, yarr)
  2. result
  3. # array([ 1.1, 2.2, 1.3, 1.4, 2.5])

np.where的第二個和第三個參數不必是數組,它們都可以是標量值。 where通常用於根據另一個數組而產生一個新的數組。假設有一個由隨機數據組成的矩陣,希望將所有正值替換為2,將所有負值為-2。利用 np.where,則會非常簡單:

  1. arr = np.random.randn(4, 4)
  2. arr
  3. # array([[ 2.18194474, 0.15001978, -0.77191684, 0.18716397],
  4. # [ 1.2083149 , -0.22911585, 1.30880201, 0.14197253],
  5. # [ 0.65639111, -1.28394185, 0.65706167, 1.14277598],
  6. # [-0.32639966, -0.26880881, -0.10225964, 0.4739671 ]])
  7. arr > 0
  8. # array([[ True, True, False, True],
  9. # [ True, False, True, True],
  10. # [ True, False, True, True],
  11. # [False, False, False, True]], dtype=bool)
  12. np.where(arr > 0, 2, -2)
  13. # array([[ 2, 2, -2, 2],
  14. # [ 2, -2, 2, 2],
  15. # [ 2, -2, 2, 2],
  16. # [-2, -2, -2, 2]])

傳給 where的數組大小可以不等,甚至是標量值:

  1. np.where(arr > 0, 2, arr)
  2. # array([[ 2. , 2. , -0.77191684, 2. ],
  3. # [ 2. , -0.22911585, 2. , 2. ],
  4. # [ 2. , -1.28394185, 2. , 2. ],
  5. # [-0.32639966, -0.26880881, -0.10225964, 2. ]])

當然還可以用 where表述出更複雜的邏輯。比如,有兩個布爾型數組cond1和cond2,希望根據4種不同的布爾值組合實現不同的賦值操作:

  1. result = []
  2. for i in rang(n):
  3. if cond1[i] and cond2[i]:
  4. result.append(0)
  5. elif cond1[i]:
  6. result.append(1)
  7. elif cond2[i]:
  8. result.append(2)
  9. else:
  10. result.append(3)

其實這個for循環可以被改寫成一個嵌套的where表達式:

  1. np.where(cond1 & cond2, 0,
  2. np.where(cond1, 1,
  3. np.where(cond2, 2, 3)))

當然,還可以利用「布爾值在計算過程中可以被當作0或1處理」這個特性,寫出下面這樣的算術運算:

  1. result = 1 * (cond1 - cond2) + 2 * (cond2 & ~cond1) + 3 * ~(cond1 | cond2)

數學和統計方法

可以通過數組上的一組數學函數對整個數組或某個軸向的數據進行統計計算。 summean以及標準差 std等聚合計算,既可以當作數組的實例方法調用,也可以當作NumPy函數使用。

用於布爾型數組的方法

在上面的這些方法中,布爾值會被強制轉換為1和0。因此, sum經常被用來對布爾型數組中的True值計數:

  1. arr = np.random.randn(100)
  2. (arr > 0).sum() # 正值的個數
  3. # 46

此外,還有兩個方法 allany,對布爾型數組非常有用。 any用來測試數組中是否存在一個或多個True,而 all用來檢查數組中所有值是否都是True:

  1. bools = np.array([False, False, True, False])
  2. bools.any()
  3. # True
  4. bools.all()
  5. # False

這兩個方法也能用於非布爾型數組,所有非0元素將會被當作True

排序

和Python內置的列表類型一樣,NumPy數組也可以通過 sort方法就地排序:

  1. arr = np.random.randn(8)
  2. arr
  3. # array([-0.12548627, 0.48416463, -0.60329322, -0.97621836, -1.40661579,
  4. # -0.94048985, 0.39240798, -0.72289484])
  5. arr.sort()
  6. arr
  7. # array([-1.40661579, -0.97621836, -0.94048985, -0.72289484, -0.60329322,
  8. # -0.12548627, 0.39240798, 0.48416463])

如要給多維數組在任何一個軸向上進行排序,只需將編號傳給 sort即可:

  1. arr = np.random.randn(5, 3)
  2. arr
  3. # array([[ 1.34474096, -0.54278373, 0.37720539],
  4. # [-0.12397085, -0.37419876, -0.3912591 ],
  5. # [ 1.14297965, -0.11538471, 1.7203057 ],
  6. # [-0.52452979, 0.18915574, 1.68349056],
  7. # [-0.42245571, 0.85141729, 0.42501451]])
  8. arr.sort(1)
  9. arr
  10. # array([[-0.54278373, 0.37720539, 1.34474096],
  11. # [-0.3912591 , -0.37419876, -0.12397085],
  12. # [-0.11538471, 1.14297965, 1.7203057 ],
  13. # [-0.52452979, 0.18915574, 1.68349056],
  14. # [-0.42245571, 0.42501451, 0.85141729]])

使用 np.sort返回的是數組的已排序副本,而就地排序則會修改數組本身

唯一化以及其他的集合邏輯

NumPy提供了一些針對一維ndarray的基本集合運算。

用於數組的文件輸入輸出

NumPy能夠讀寫磁碟上的文本數據或二進位數據。

將數組以二進位格式保存到磁碟

np.savenp.load是讀寫磁碟數組數據的兩個主要函數。默認情況下,數組是以未壓縮的原始二進位格式保存在擴展名為.npy的文件中。

  1. arr = np.arange(10)
  2. np.save(some_array, arr)
  3. np.load(ome_array.npy)
  4. # array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

文件末尾沒加擴展名.npy會被自動加上,然後通過 np.load來讀取。

np.savez能保存多個數組,將數組以關鍵字參數的形式傳入即可,不過是未壓縮的npz格式:

  1. np.savez(array_archive.npz, a=arr, b=arr)
  2. arch = np.load(array_archive.npz)
  3. arch[b]
  4. # array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

載入.npz文件的時,得到一個類似字典的對象。

可以用 np.savez_compressed來壓縮文件,用法和 np.savez類似。

存取文本文件

使用 np.loadtxt即將文本文件可載入到NumPy數組中, np.savetxt起相反作用。

np.genfromtxtnp.loadtxt差不多,只不過面向的是結構化數組和缺失數據處理。

線性代數

NumPy也支持線性代數的內容。

隨機數生成

numpy.random模塊對Python內置的random進行了補充,增加了一些用於高效生成多種概論分布的樣本值函數。Python內置的random模塊一次只能生成一個樣本值,numpy.random一次可生成多個。如果需要產生大量樣本值,numpy。random快了不止一個數量級。

推薦閱讀:

擴散方程
方勢阱薛定諤方程
Python科學計算與自動控制1-Python入門
功能富足,足夠優美的科學計算神器-Archimedes Calculator #iOS #Android
Python裡面的scipy庫如何計算線性規劃問題呢?

TAG:Python | numpy | 科学计算 |