什麼是 NumPy
NumPy 是 Numeric Python(or Numerical Python)的簡稱,是 Python 最重要的資料科學模組之一。NumPy 創造了 ndarray
的資料結構類別以及大量的通用函數與聚合函數,讓 Python 使用者能夠對數列進行快速的數值計算、對數列使用統計函數、進行線性代數運算以及操作隨機的模擬任務等。NumPy 的前身為兩個模組,都是在 1990 年代中期所誕生的 Numeric
與 Numarray
模組,NumPy 於 2005 年集兩者之大成問世。對 NumPy 模組的發展歷史有興趣的讀者可以進一步參考 Array Programming with NumPy1 以及 NumPy - Wikipedia2。
安裝與載入 NumPy
NumPy 的安裝可以透過 pip 或者 conda,如果讀者的 Python 是從 Python.org 下載的就直接透過 pip 安裝,假如是約維安計畫的成員,Python 應該是 Miniconda 版本,那麼建議可以透過 conda 安裝3。
$ pip install numpy==MAJOR.MINOR.PATCH
$ conda install numpy==MAJOR.MINOR.PATCH
如果希望從既有的 NumPy 版本更新升級,可以在 install
指令之後加上 -U
或 --update-deps
參數。
$ pip install -U numpy==MAJOR.MINOR.PATCH
$ conda install -c conda-forge --update-deps numpy==MAJOR.MINOR.PATCH
官方文件建議載入模組的所有功能並且縮寫為 np
。
import numpy as np
利用兩個模組內建屬性檢視 NumPy 的安裝版本與路徑。
print(np.__version__)
print(np.__file__)
怎樣學好 NumPy
學好 NumPy 的關鍵是理解其核心功能以及主要應用場景:
如何使用
ndarray
來進行數值操作。如何使用 NumPy 定義的函數對
ndarray
進行數值運算。如何應用
ndarray
於向量、矩陣以及張量的操作及運算。ndarray
是其他資料科學模組 Pandas、Matplotlib 與 Scikit-Learn 的基石。
如何創造 ndarray
常見兩種創造 ndarray
的方式有:從既有的 list
創造或者利用函數創造。
# Create ndarray from a list
prime_list = [2, 3, 5, 7, 11]
prime_array = np.array(prime_list)
print(prime_array)
print(type(prime_array))
利用 NumPy 定義的函數可以創造出內容元素相同、數列型態以及具備特定分配的 ndarray
。
# Create ndarray with identical elements
print(np.zeros(5, dtype=int))
print(np.ones(5, dtype=float))
print(np.full(5, 6))
# Create ndarray as a sequence
print(np.arange(1, 11, 2))
print(np.linspace(1, 9, 5, dtype=int))
# Create ndarray with a specific distribution
m = 10000
uniform_array = np.random.random(m)
normal_array = np.random.normal(0, 1, m)
randint_array = np.random.randint(1, 7, size=m)
print(uniform_array)
print(normal_array)
print(randint_array)
常用的 ndarray 屬性
常用的 ndarray
屬性有四個,分別是:
ndarray.ndim
維度數。ndarray.shape
外型。ndarray.size
元素個數。ndarray.dtype
資料類別。
print(prime_array.ndim)
print(prime_array.shape)
print(prime_array.size)
print(prime_array.dtype)
從 ndarray 中擷取元素、片段的方式
利用與 list
相同的 indexing/slicing 語法。
print(prime_array[0]) # indexing
print(prime_array[0:3:1]) # slicing
利用 ndarray
的特性,在中括號使用多個索引取得指定位置的元素。
matrix = np.array([[5, 5],
[6, 6],
[55, 66]])
print(matrix[2, 1])
利用 ndarray
的特性,能夠以 Fancy indexing 或 Boolean indexing 的方式取得指定位置、符合指定條件的元素。Fancy indexing(華麗索引?)指的是以一個 list
決定要取得哪些位置的元素,Boolean indexing 指的是以一個外型相同、充滿布林值的 ndarray
來取得對應位置為 True
的元素。
# Fancy indexing
print(prime_array[[0, 1, 4]])
# Boolean indexing
print(prime_array % 2 == 1)
print(prime_array[prime_array % 2 == 1])
常用的 ndarray 操作
我們常對 ndarray
進行的操作有調整外型、合併以及分割。使用 ndarray
的 reshape()
方法調整成指定外型,在其他維度已經決定時可以方便地指定 -1
給最後一個維度;使用 ndarray
的 ravel()
方法打平成一維。
array_range = np.arange(1, 13)
print(array_range) # (12,)
print(array_range.reshape(3, 4)) # (3, 4)
print(array_range.reshape(3, -1)) # (3, 4)
print(array_range.reshape(-1, 4)) # (3, 4)
print(array_range.reshape(3, 4).ravel()) # (12,)
合併操作能夠透過 np.concatenate()
函數達成,預設為垂直方向的合併(增加列數),指定參數 axis=1
則能夠調整為水平方向的合併(增加欄位)。
array_a = np.arange(1, 5).reshape(2, 2)
array_b = np.arange(5, 9).reshape(2, 2)
print(np.concatenate((array_a, array_b)))
print(np.concatenate((array_a, array_b), axis=1))
分割操作能夠透過 np.split()
函數達成,預設為垂直方向的分割,指定參數 axis=1
則能夠調整為水平方向的分割。
array_range = np.arange(20).reshape(-1, 2)
upper_array, lower_array = np.split(array_range, 2)
left_array, right_array = np.split(array_range, 2, axis=1)
print(upper_array)
print(lower_array)
print(left_array)
print(right_array)
NumPy 的數值運算函數
NumPy 提供非常豐富、能夠針對 ndarray
進行運算的通用函數、聚合函數。通用函數是具備向量化(Vectorized)特性的函數,接受固定數量、外型的輸入並對應相同數量、外型的輸出。
array_range = np.arange(10)
print(np.power(array_range, 2))
print(np.exp(array_range))
如果需要自行定義能夠對 ndarray
運算應用的通用函數,可以使用 np.vectorize()
函數將只能作用於純量的函數轉換為能作用於 ndarray
的通用函數。
def is_prime(x):
number_of_divisors = 0
for integer in range(1, x + 1):
if x % integer == 0:
number_of_divisors += 1
return number_of_divisors == 2
vectorized_is_prime = np.vectorize(is_prime)
vectorized_is_prime(np.arange(10))
聚合函數則是能夠將多個資料值輸入摘要為單一值輸出的函數,在使用 NumPy 的聚合函數時有兩個值得注意的特性:可以沿指定的軸(axis)進行聚合、針對含有 np.nan
(Not a Number)的 ndarray
有相對應名稱的聚合函數可以運算。
# Aggregate along specific axis
array_range = np.arange(1, 16, dtype=float).reshape(3, 5)
print(np.sum(array_range))
print(np.sum(array_range, axis=0))
print(np.sum(array_range, axis=1))
# Similar function names for array with np.nan
array_range[2, 4] = np.nan
print(array_range)
print(np.sum(array_range))
print(np.nansum(array_range))
入門 NumPy 之後,我們就能夠在下次的電子報中透過 ndarray 認識線性代數最重要的內容:矩陣運算。
在認識了 NumPy 的核心功能以及主要應用場景之後,第三十三週約維安計畫:NumPy 來到尾聲,希望您也和我一樣期待下一篇文章。
對於這篇文章有什麼想法呢?喜歡😻、留言🙋♂️或者分享🙌