NumPy

NumPy (Numerical Python) 簡(jiǎn)介:高性能科學(xué)計(jì)算基石

1. 什么是 NumPy?

NumPy (Numerical Python) 是 Python 語言中進(jìn)行科學(xué)計(jì)算的基礎(chǔ)庫。它提供了一個(gè)高性能的多維數(shù)組對(duì)象(ndarray以及操作這些數(shù)組的工具。

在 Python 的數(shù)據(jù)科學(xué)生態(tài)系統(tǒng)中,NumPy 是基石。幾乎所有高級(jí)庫(如 Pandas、Matplotlib、SciPy、Scikit-learn、TensorFlow 和 PyTorch)都依賴于 NumPy 的數(shù)據(jù)結(jié)構(gòu)進(jìn)行高效的數(shù)據(jù)處理。它為處理大規(guī)模數(shù)據(jù)集提供了優(yōu)化的底層結(jié)構(gòu),是數(shù)據(jù)科學(xué)家和工程師不可或缺的工具。

2. 為什么選擇 NumPy?(核心優(yōu)勢(shì))

相比于 Python 原生的 list,NumPy 在處理大規(guī)模數(shù)值數(shù)據(jù)時(shí)具有顯著的優(yōu)勢(shì),這些優(yōu)勢(shì)源于其獨(dú)特的設(shè)計(jì)哲學(xué)和底層實(shí)現(xiàn):

  1. 速度與內(nèi)存效率:

    • 內(nèi)存連續(xù)性與局部性: ndarray 數(shù)組將數(shù)據(jù)存儲(chǔ)在連續(xù)的內(nèi)存塊中。這種結(jié)構(gòu)確保了內(nèi)存局部性(Locality of Reference),使得 CPU 緩存(Cache)能夠高效地預(yù)取數(shù)據(jù),從而大大加快了數(shù)據(jù)讀取和處理速度。

    • 數(shù)據(jù)同構(gòu)性: 數(shù)組是同構(gòu)的(Homogeneous),意味著所有元素的數(shù)據(jù)類型相同(例如,都是 [圖片上傳中...(image-5474b3-1760165947694-16)]

      位浮點(diǎn)數(shù),float64)。這消除了 Python 在運(yùn)行時(shí)進(jìn)行頻繁類型檢查的開銷,使得內(nèi)存占用更小,計(jì)算效率更高。

    • C 語言加速與 SIMD: NumPy 的底層核心算法使用了高效的 C/C++/Fortran 語言實(shí)現(xiàn),并利用了現(xiàn)代 CPU 的 SIMD(Single Instruction, Multiple Data,單指令多數(shù)據(jù))指令集,能夠并行處理多個(gè)數(shù)據(jù)點(diǎn),使得在執(zhí)行復(fù)雜的數(shù)值運(yùn)算時(shí),其速度遠(yuǎn)超純 Python 循環(huán)。

  2. 向量化操作(Vectorization):

    • NumPy 允許您對(duì)整個(gè)數(shù)組執(zhí)行數(shù)學(xué)運(yùn)算,而無需編寫顯式的 Python 循環(huán)(例如 for 循環(huán))。

    • 這種元素級(jí)(element-wise)的操作,例如數(shù)組相加或乘以標(biāo)量,直接映射到底層優(yōu)化的 C 函數(shù)調(diào)用,極大地簡(jiǎn)化了代碼結(jié)構(gòu),同時(shí)將性能優(yōu)化推到極致。

  3. 豐富的工具集:

    • 提供了大量的通用函數(shù)(ufunc),它們是作用于 ndarray 對(duì)象的快速函數(shù)。這些函數(shù)涵蓋了三角函數(shù)、指數(shù)、對(duì)數(shù)、數(shù)學(xué)、統(tǒng)計(jì)、線性代數(shù)等科學(xué)計(jì)算的必備功能,提供了對(duì)數(shù)組操作的高級(jí)抽象。

3. NumPy 的核心:ndarray 對(duì)象深度解析

ndarray 是 NumPy 的核心數(shù)據(jù)結(jié)構(gòu),它是一個(gè)同構(gòu)固定大小的多維數(shù)組。

3.1 數(shù)組的基本屬性與數(shù)據(jù)類型 (Dtype)

一個(gè) ndarray 實(shí)例的關(guān)鍵屬性,以及其數(shù)據(jù)類型的重要性:

| 屬性 | 描述 (中文) | 描述 (英文) | 示例 |
|

.ndim

|

數(shù)組的維數(shù)(或軸數(shù))。

|

[圖片上傳中...(image-668f84-1760165947694-15)]

-dimensions

|

三維張量為 [圖片上傳中...(image-ad954c-1760165947694-14)]

[圖片上傳中...(image-b363b6-1760165947694-13)]

|
|

.shape

|

數(shù)組的維度大?。烤S的長(zhǎng)度)。

|

Shape (e.g., [圖片上傳中...(image-21fea-1760165947694-12)]

)

|

[圖片上傳中...(image-8d500f-1760165947694-11)]

個(gè) [圖片上傳中...(image-d27834-1760165947694-10)]

矩陣的形狀

|
|

.size

|

數(shù)組中元素的總個(gè)數(shù)。

|

Total elements

|

[圖片上傳中...(image-d885ed-1760165947694-9)]

[圖片上傳中...(image-706db2-1760165947694-8)]

|
|

.dtype

|

數(shù)組中元素的類型。

|

Data Type

|

int32, float64, bool

|

數(shù)據(jù)類型 (dtype) 的重要性:

精確選擇 dtype 可以顯著影響內(nèi)存占用和計(jì)算速度。例如,存儲(chǔ) [圖片上傳中...(image-a48126-1760165947695-24)]

萬個(gè)整數(shù),使用 np.int32 比默認(rèn)的 np.int64 可以節(jié)省一半的內(nèi)存空間。常用的 dtype 包括 np.int64 (默認(rèn)整數(shù)), np.float64 (默認(rèn)浮點(diǎn)數(shù)), np.bool_, 和 np.complex128 (復(fù)數(shù))。在科學(xué)計(jì)算中,通常使用 np.float64 來保證高精度。

3.2 數(shù)組的創(chuàng)建與初始化

NumPy 提供了靈活的數(shù)組創(chuàng)建方式:

import numpy as np

# 1\. 指定數(shù)據(jù)類型創(chuàng)建數(shù)組 (使用 8 位無符號(hào)整數(shù))
matrix_a = np.array([[10, 20], [30, 40]], dtype=np.uint8)

# 2\. 創(chuàng)建全 0 數(shù)組 (3 維: 2個(gè) 2x3 的矩陣)
arr_b = np.zeros((2, 2, 3)) 

# 3\. 創(chuàng)建等間隔數(shù)組: log 空間等間隔
arr_c = np.logspace(0, 1, 5) 
# arr_c 在 10^0 到 10^1 之間生成 5 個(gè)均勻間隔的數(shù)

# 4\. 創(chuàng)建對(duì)角矩陣 (對(duì)角線為 [1, 2, 3])
diag_matrix = np.diag([1, 2, 3]) 

# 5\. 創(chuàng)建隨機(jī)數(shù)組:從 [0, 10) 中抽取 9 個(gè)隨機(jī)整數(shù),并重塑為 3x3
random_integers = np.random.randint(0, 10, size=9).reshape(3, 3)

print(f"matrix_a 的數(shù)據(jù)類型: {matrix_a.dtype}") # uint8
print(f"diag_matrix:\n{diag_matrix}")

3.3 數(shù)組索引、切片與高級(jí)索引

NumPy 提供了三種主要的索引機(jī)制:

  1. 基本切片 (Basic Slicing): 類似于 Python 列表,使用 : 來選擇連續(xù)的元素。切片操作返回的是視圖。

  2. 布爾索引 (Boolean Indexing): 使用一個(gè)與原數(shù)組形狀相同(或可廣播)的布爾數(shù)組作為掩碼,來選擇所有值為 True 的元素。

  3. 花式索引(Fancy Indexing / 整數(shù)數(shù)組索引): 使用整數(shù)數(shù)組或列表來指定要選擇的行和列的索引。花式索引返回的是數(shù)據(jù)的副本。

A = np.arange(9).reshape(3, 3) 
# A = [[0, 1, 2], 
#      [3, 4, 5],
#      [6, 7, 8]]

# 1\. 基本切片
sub_matrix = A[:2, 1:] 
# sub_matrix = [[1, 2], [4, 5]]

# 2\. 布爾索引:篩選出所有大于 5 的元素
mask = A > 5
filtered_values = A[mask] # [6, 7, 8]

# 3\. 花式索引:選擇 (0, 0), (1, 2), (2, 1) 這三個(gè)坐標(biāo)的元素
rows = np.array([0, 1, 2])
cols = np.array([0, 2, 1])
selected = A[rows, cols] # [0, 5, 7]

3.4 視圖 (View) 與副本 (Copy) 的區(qū)別

這是 NumPy 中最容易引起混淆的概念之一,因?yàn)樗苯雨P(guān)系到數(shù)據(jù)的修改。

  • 視圖 (View):

    • 定義: 切片操作(如 arr[:])和 .reshape()、.T (轉(zhuǎn)置) 通常返回原始數(shù)組的一個(gè)視圖。

    • 影響: 視圖只是一個(gè)指向原始數(shù)據(jù)的新指針(共享內(nèi)存)。因此,對(duì)視圖的任何修改都會(huì)直接改變原始數(shù)組的數(shù)據(jù)。

  • 副本 (Copy):

    • 定義: 使用 .copy() 方法或某些操作(如花式索引、flatten())會(huì)創(chuàng)建一個(gè)新的數(shù)組。

    • 影響: 副本在內(nèi)存中分配了新的數(shù)據(jù)空間。對(duì)副本的修改不會(huì)影響原始數(shù)組。

理解何時(shí)是視圖、何時(shí)是副本,對(duì)于避免意外修改原始數(shù)據(jù)至關(guān)重要。

original_arr = np.arange(4) # [0, 1, 2, 3]

# 示例 1: 切片 (View)
view_arr = original_arr[1:3] # [1, 2]
view_arr[0] = 99 
# 原始數(shù)組被改變: original_arr 變?yōu)?[0, 99, 2, 3]

# 示例 2: 顯式復(fù)制 (Copy)
copy_arr = original_arr.copy() 
copy_arr[0] = 100 
# original_arr 不變,仍然是 [0, 99, 2, 3]

4. 通用函數(shù)(Universal Functions, UFuncs)

通用函數(shù)(UFuncs) 是 NumPy 的核心概念,它們是快速的、元素級(jí)的操作包裝器。所有基本的數(shù)學(xué)運(yùn)算(加、減、乘、除)和大多數(shù)數(shù)學(xué)函數(shù)都是 UFuncs。

4.1 數(shù)學(xué)與三角函數(shù) UFuncs

這些函數(shù)對(duì)數(shù)組中的每個(gè)元素獨(dú)立進(jìn)行計(jì)算,完美體現(xiàn)了向量化操作的威力。

| 函數(shù) | 描述 |
|

np.exp()

|

指數(shù)函數(shù) [圖片上傳中...(image-59a636-1760165947694-7)]

[圖片上傳中...(image-5a32b-1760165947694-6)]

|
|

np.sqrt()

|

平方根

|
|

np.sin() / np.cos()

|

三角函數(shù)

|
|

np.floor() / np.ceil()

|

向下/向上取整

|
|

np.maximum(A, B)

|

計(jì)算兩個(gè)數(shù)組(或數(shù)組和標(biāo)量)中對(duì)應(yīng)位置的最大值

|

4.2 比較與邏輯 UFuncs

UFuncs 也包括了元素級(jí)的比較操作,這些操作返回布爾數(shù)組,常用于創(chuàng)建布爾掩碼。

data_a = np.array([1, 5, 10])
data_b = np.array([2, 4, 8])

# 元素級(jí)比較
comparison = data_a > data_b 
# comparison = [False, True, True]

# 邏輯操作(對(duì)布爾數(shù)組進(jìn)行操作)
is_large = (data_a > 4) & (data_a < 11) 
# is_large = [False, True, True]

# 使用 np.maximum 找到兩個(gè)數(shù)組中更大的值
max_values = np.maximum(data_a, data_b) # [2, 5, 10]

5. 向量化運(yùn)算與廣播機(jī)制(Broadcasting)詳解

5.1 廣播機(jī)制 (Broadcasting)

廣播是 NumPy 允許不同形狀的數(shù)組在特定條件下進(jìn)行算術(shù)運(yùn)算的機(jī)制。它通過虛擬地?cái)U(kuò)展(不是實(shí)際復(fù)制內(nèi)存)較小數(shù)組的維度來匹配較大數(shù)組的形狀。

核心兼容性規(guī)則: 從數(shù)組的末尾維度開始比較,如果兩個(gè)數(shù)組的維度滿足以下任一條件,則兼容:

  1. 維度相等。

  2. 其中一個(gè)維度為 [圖片上傳中...(image-63c102-1760165947694-19)]

  3. 其中一個(gè)數(shù)組缺少該維度(NumPy 會(huì)在左側(cè)自動(dòng)添加維度 [圖片上傳中...(image-7b6976-1760165947694-18)]

    )。

5.2 復(fù)雜廣播示例

A = np.arange(3).reshape(3, 1) # 形狀 (3, 1)
B = np.arange(3)             # 形狀 (3,) -> 擴(kuò)展為 (1, 3)

# 形狀比較:
# A.shape: (3, 1)
# B.shape: (1, 3) 
# 維度 1: 1 和 3 -> 兼容 (1 被擴(kuò)展到 3)
# 維度 2: 3 和 1 -> 兼容 (1 被擴(kuò)展到 3)

Result = A + B
# 結(jié)果形狀為 (3, 3)

# Result = [[0, 1, 2],
#           [1, 2, 3],
#           [2, 3, 4]]

print(f"A:\n{A}")
print(f"B:\n{B}")
print(f"A + B 的形狀: {Result.shape}")
print(f"廣播結(jié)果:\n{Result}")

6. 聚合函數(shù)與軸 (Axis) 的概念

6.1 軸 (Axis) 的直觀理解

軸 (Axis) 定義了聚合操作發(fā)生的方向。在 [圖片上傳中...(image-8baa12-1760165947695-23)]

維數(shù)組中,axis=k 意味著操作將沿著第 [圖片上傳中...(image-61160d-1760165947695-22)]

個(gè)軸進(jìn)行壓縮或計(jì)算,該維度將從結(jié)果的形狀中移除。

  • 對(duì)于二維數(shù)組:axis=0的方向,axis=1的方向。

  • 對(duì)于三維數(shù)組 (例如:圖像數(shù)據(jù) [圖片上傳中...(image-47e7fe-1760165947694-17)]

    ):axis=0 壓縮高度,axis=2 壓縮顏色通道。

6.2 擴(kuò)展聚合函數(shù)

NumPy 提供了強(qiáng)大的統(tǒng)計(jì)工具:

| 函數(shù) | 描述 |
|

arr.mean()

|

均值

|
|

arr.std()

|

標(biāo)準(zhǔn)差

|
|

np.median(arr)

|

中位數(shù)

|
|

np.percentile(arr, q)

|

計(jì)算第 q

百分位數(shù)

|
|

arr.argmax(axis)

|

返回指定軸上的最大值索引

|

data_stats = np.array([[10, 20, 30], 
                       [15, 25, 35]]) 

# 沿著 axis=0 (列) 計(jì)算均值
mean_cols = data_stats.mean(axis=0) 
# mean_cols = [12.5, 22.5, 32.5]

# 沿著 axis=1 (行) 計(jì)算最大值索引
max_index_rows = data_stats.argmax(axis=1) 
# max_index_rows = [2, 2] (每行最大值索引)

7. 案例應(yīng)用:數(shù)據(jù)標(biāo)準(zhǔn)化(Z-Score Normalization)

數(shù)據(jù)標(biāo)準(zhǔn)化([圖片上傳中...(image-8c62f9-1760165947695-21)]

-Score)是數(shù)據(jù)預(yù)處理中的常見步驟:[圖片上傳中...(image-56b576-1760165947695-20)]

。這個(gè)過程完美展示了 NumPy 的聚合、向量化和廣播機(jī)制。

# 假設(shè)有一個(gè) 100 行 5 列的特征矩陣 (100 個(gè)樣本, 5 個(gè)特征)
X = np.random.randn(100, 5) * 5 + 10 # 隨機(jī)數(shù)據(jù),均值約 10,標(biāo)準(zhǔn)差約 5

# 步驟 1: 沿著樣本軸 (axis=0) 計(jì)算每個(gè)特征的平均值 (μ)
mean = X.mean(axis=0) # 形狀 (5,)

# 步驟 2: 沿著樣本軸 (axis=0) 計(jì)算每個(gè)特征的標(biāo)準(zhǔn)差 (σ)
std = X.std(axis=0) # 形狀 (5,)

# 步驟 3: 使用廣播機(jī)制進(jìn)行 Z-Score 標(biāo)準(zhǔn)化
# X (100, 5) - mean (5,) -> mean 廣播到 (100, 5)
# (X - mean) / std -> std 廣播到 (100, 5)
X_standardized = (X - mean) / std 

print(f"原始數(shù)據(jù)形狀: {X.shape}")
print(f"均值形狀: {mean.shape}")
print(f"標(biāo)準(zhǔn)化后的數(shù)據(jù)的均值 (接近 0):\n{X_standardized.mean(axis=0).round(4)}")
print(f"標(biāo)準(zhǔn)化后的數(shù)據(jù)的標(biāo)準(zhǔn)差 (接近 1):\n{X_standardized.std(axis=0).round(4)}")

8. 高級(jí)模塊:線性代數(shù)與隨機(jī)數(shù)

8.1 線性代數(shù) (np.linalg)

np.linalg 模塊提供了線性代數(shù)所需的核心工具,用于解決矩陣運(yùn)算和系統(tǒng)分析問題。

L = np.array([[4, 2], [1, 3]])

# 1\. 計(jì)算行列式
determinant = np.linalg.det(L) # 10.0

# 2\. 計(jì)算特征值和特征向量 (Eigenvalues and Eigenvectors)
eigen_values, eigen_vectors = np.linalg.eig(L)

print(f"行列式: {determinant}")
print(f"特征值: {eigen_values}") 

8.2 隨機(jī)數(shù)生成與采樣 (np.random)

NumPy 的 np.random 模塊用于高效生成各種分布的隨機(jī)數(shù),是進(jìn)行數(shù)據(jù)模擬和模型初始化的基礎(chǔ)。

| 函數(shù) | 描述 |
|

np.random.uniform(low, high, size)

|

均勻分布 [圖片上傳中...(image-f33d9a-1760165947694-4)]

[圖片上傳中...(image-441b28-1760165947694-3)]

|
|

np.random.normal(loc, scale, size)

|

正態(tài)(高斯)分布,均值 [圖片上傳中...(image-b73d3a-1760165947694-2)]

,標(biāo)準(zhǔn)差 [圖片上傳中...(image-9f9aa3-1760165947694-1)]

[圖片上傳中...(image-1beb25-1760165947694-0)]

|
|

np.random.permutation(arr)

|

返回?cái)?shù)組的隨機(jī)排列(洗牌)

|

9. 數(shù)據(jù)持久化:數(shù)組的保存與加載

對(duì)于大型的 NumPy 數(shù)組,為了避免重復(fù)計(jì)算,我們需要將其保存到磁盤。

| 方法 | 文件格式 | 描述 |
|

np.save() / np.load()

|

.npy (NumPy 專用二進(jìn)制格式)

|

保存單個(gè)數(shù)組,速度最快,能夠精確地保留數(shù)組的 dtype 和形狀信息。

|
|

np.savetxt() / np.loadtxt()

|

.txt.csv

|

保存和加載文本文件,雖然易于閱讀,但在處理大型數(shù)組時(shí)速度較慢且可能丟失精度。

|
|

np.savez()

|

.npz (壓縮的 NumPy 格式)

|

將多個(gè)數(shù)組保存到一個(gè)壓縮文件中,適合存儲(chǔ)整個(gè)數(shù)據(jù)集。

|

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容