如果你曾經用過 Python 的 list
處理大量數字,
一定會有這種感覺:
「我只是想把每個數字乘以 2,結果 for 迴圈寫了十行,還慢得要命!!」
登愣!這就是 NumPy 誕生的原因!
NumPy,全名 Numerical Python,
是一個用來「加速數值計算」的第三方套件。
它能幫我們:
因為底層是用 C 語言 寫的!!
而且它的陣列結構是連續記憶體,不像 Python list 那樣東一塊西一塊。
所以運算起來超順暢~幾十萬筆資料在它眼中只是小菜一碟。
幾乎所有跟數字、資料或 AI 有關的領域都離不開它:
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]])
print(a)
輸出:
說明:
這裡的 a
就是 ndarray,
一種比 list
更高效、更聰明的陣列型態。
你可以利用以下的語法快速查看它的屬性:
print(a.ndim) # 維度數量
print(a.shape) # 各維度大小
print(a.size) # 元素總數
print(a.dtype) # 資料型態
輸出:
補充:
list 裡的元素可以混合不同型態,
但 ndarray 所有元素都必須是相同型態,
這就是它能「又快又省」的祕密!
想要什麼樣的陣列?NumPy 都幫你準備好了。
函式 | 說明 |
---|---|
np.zeros((3,4)) |
全部填 0 |
np.ones((2,3)) |
全部填 1 |
np.full((2,2), 7) |
全部填 7 |
np.eye(3) |
單位矩陣 |
np.diag([1,2,3]) |
對角線為指定值 |
我們來一一的介紹!
# 1. 生成全零陣列
zeros_arr = np.zeros((2, 3)) # 2x3 的全零矩陣
print("全零陣列:\n", zeros_arr)
輸出:
# 2. 生成全一陣列
ones_arr = np.ones((3, 2)) # 3x2 的全一矩陣
print("全一陣列:\n", ones_arr)
輸出:
# 3. 生成全部為指定數字的陣列
full_arr = np.full((2, 2), 7) # 2x2,全是 7
print("\n全 7 陣列:\n", full_arr)
輸出:
#4.建立對角矩陣,對角皆1,其餘為0
indentity_matrix = np.eye(3)
print('eye:')
print(indentity_matrix)
輸出:
#5.建立對角矩陣,斜對角為指定的數字
diag_matrix = np.diag([1,2,3])
print(diag_matrix)
輸出:
懶得自己打數字?交給電腦生!
arange()
vs linspace()
:一個像走路、一個像切片這兩個函式都可以「自動產生一串數字」,但概念其實完全不一樣。
我們用生活例子來比喻:
np.arange(start, stop, step)
:像「走樓梯」「從起點開始,每次走固定的步伐,直到終點前停下。」
範例:
import numpy as np
print(np.arange(1, 10, 2))
輸出:
說明:
就像「我從 1 樓開始,每次走 2 層,到 10 樓之前就停」。所以最後停在9樓。
np.arange()用的是固定步長,
所以如果你給它「小數間隔」,有時會出現浮點誤差!
(例:np.arange(0, 1, 0.1),可能出現 0.30000004 之類的值 )
到這邊為止,不曉得讀者有沒有和我有一樣的感覺,
這個np.arange()感覺有點似曾相識對吧!!
沒錯!!就是我們之前學的range()
我們來介紹一下他們到底差在哪?
range()
vs np.arange()
:雖然名字很像,但 range()
是 Python 內建的,np.arange()
則是 NumPy 家族的一員。
它們都能「產生一串連續的數字」,但背後的邏輯與用途其實完全不同。
比較項目 | range() |
np.arange() |
---|---|---|
所屬套件 | Python 內建 | Numpy 模組 |
是否需 import | 不需 | 需先 import numpy as np |
回傳型態 | <class 'range'> |
<class 'numpy.ndarray'> |
可否用 float 步長 | 否 | 可以 |
是否可直接運算 | 否(需轉 list) | 可直接運算 |
是否支援多維陣列 | 否 | 可 reshape 成多維 |
共同點 | 都有 start、stop、step 三參數,左閉右開 [start, stop) ,都能用在 for 迴圈 |
簡單來說:
range()
回傳的是「一個會產生數字的物件」(不是陣列)np.arange()
則直接幫你生出一整個 Numpy 陣列。np.linspace(start, stop, num)
:像「切蛋糕」「我知道蛋糕的頭和尾,要切成幾等份。」
範例:
print(np.linspace(1, 10, 5))
輸出:
想像你有一條 1 到 10 的數線,
你說「幫我平均切成 5 段」,NumPy 就幫你生出 5 個等距的數字(包含頭尾)。
小提醒:linspace
是固定分段數,而不是固定間隔。
所以它在繪圖、取樣(像畫 sin 波、時間軸)時特別常用。
最後我做了一張slide來做個小總結:
當你想改變資料的「外觀」時,就用這兩個。
a = np.arange(6)
print(a)
print("==我是分隔線==")
print(a.reshape(2,3))
print("==我是分隔線==")
print(np.resize(a, (3,2)))
輸出:
NumPy 支援更靈活的取值方式:
a = np.array([[1,2,3],[4,5,6],[7,8,9]])
print("取第2列第3欄的值:",a[1,2])
print("取所有列的第2欄:",a[:,1])
a[1,2] = 99 # 修改
print("修改過後:",a)
輸出:
同時也支援切片與倒序:
print("切片:")
print(a[0:2, 1:3])
print("==我是分隔線==")
print("倒序:")
print(a[::-1])
輸出:
這裡是 NumPy 的主場,不用 for 迴圈!直接算:
a = np.array([[1,2,3],[4,5,6]])
b = np.array([10,10,10])
print(a + b)
print("==我是分隔線==")
print(a - b)
print("==我是分隔線==")
print(a * b)
print("==我是分隔線==")
print(a / b)
輸出:
除了用運算符號,也可以用語法:
import numpy as np
a = np.array([[1,2,3],[4,5,6],[7,8,9]])
b = np.array([10,10,10])
c = np.add(a,b)
print(c)
print()
d = np.subtract(a,b)
print(d)
print()
f = np.multiply(a,b)
print(f)
print()
g = np.divide(a,b)
print(g)
print()
輸出:
也可以進行四捨五入的運算喔!!
x = np.array([1.5, 2.5, -0.5, 0.5])
print(np.around(x)) # 四捨五入到最近偶數
print("====我是分隔線====")
print(np.floor(x)) # 無條件捨去
print("====我是分隔線====")
print(np.ceil(x)) # 無條件進位
輸出:
補充:
np.around()的特性:
IEEE 754 標準下,1.5 和 2.5 都會捨入偶數的整數!
a = np.array([[0,30,45],[60,75,90]])
print(np.sum(a)) # 總和
print(np.min(a)) # 最小值
print(np.max(a)) # 最大值
print(np.mean(a)) # 平均值
print(np.median(a)) # 中位數
輸出:
import numpy as np
# 假設已知資料
prices = np.array([100, 200, 150, 80, 120]) # 每種藥品單價(元)
sold = np.array([30, 15, 40, 20, 10]) # 每種藥品當日銷售數量(盒)
# 計算每種藥品的總營收
total_revenue_per_product = prices * sold
print("每種藥品的總營收:", total_revenue_per_product)
# 輸出全部藥品的總營收
total_revenue = total_revenue_per_product.sum()
print("全部藥品的總營收:", total_revenue)
# 計算平均售價
average_price = prices.mean()
print("平均售價:", average_price)
輸出:
我們可以看一下差別:假設要把數字們都平方
#與list的差別
import numpy as np
# ===== 用 list 的作法 =====
my_list = [1, 2, 3, 4, 5]
list_squared = []
for num in my_list:
list_squared.append(num ** 2)
print("list 平方結果:", list_squared) # [1, 4, 9, 16, 25]
# ===== 用 NumPy 的作法 =====
arr = np.array([1, 2, 3, 4, 5])
print("NumPy 平方結果:", arr ** 2) # [ 1 4 9 16 25 ]
有發現嗎?用list還需要搭配for-loop,
但Numpy的話直接兩行結束!!!(超快速)
如果你看到這裡,恭喜你!
我們今天正式踏進了數值計算的世界 🎉
老實說,第一次接觸 NumPy 的時候我也想過:
「有需要再學這個語法嗎?我乖乖用 list 搭配 for-loop 不也能跑出結果?」
但真的動手跑過一次,你就會發現 ——
這玩意兒不只是「快」,是超級快。
而且程式碼變得乾淨、聰明又漂亮,
尤其在做大型專案的時候,那個差距真的很有感!!
NumPy 就像幫你裝上了加速引擎,
讓原本吃力的數字處理變得優雅又順暢!
明天,我們要繼續深入「數據分析」的世界!
其實我猶豫了很久要在最後幾天介紹什麼主題,
但後來想到,會來看這個系列的朋友,大多都是剛入門的初學者,
所以我決定帶大家一起學一個「人人都能上手」的主題 —— 資料分析!
在大學裡、在各種領域中,
不論你讀商管、社科、甚至設計,
都會接觸到「用 Python 做資料分析」這件事~
明天,我們就要開始親手玩玩看~
那我們就明天見囉!!
(又是一篇快一萬字的文)