簡介
一個用python實現的科學計算,包括:
1、一個強大的N維陣列物件Array;
2、比較成熟的(廣播)函式庫;
3、用於整合C/C++和Fortran程式碼的工具包;
4、實用的線性代數、傅立葉變換和隨機數生成函式。
numpy和稀疏矩陣運算包scipy配合使用更加方便。NumPy(Numeric Python)提供了許多高階的數值程式設計工具,如:矩陣資料型別、向量處理,以及精密的運算庫。專為進行嚴格的數字處理而產生。多為很多大型金融公司使用,以及核心的科學計算組織如:Lawrence Livermore,NASA用其處理一些本來使用C++,Fortran或Matlab等所做的任務。
NumPy 的前身為 Numeric ,最早由 Jim Hugunin 與其它協作者共同開發,2005 年,Travis Oliphant 在 Numeric 中結合了另一個同性質的程式庫 Numarray 的特色,並加入了其它擴充套件而開發了 NumPy。NumPy 為開放原始碼並且由許多協作者共同維護開發。
使用方法
NumPy 是一個強大的 Python 庫,廣泛用於科學計算和資料處理。以下是一些 NumPy 在資料處理時常用的主要函式,以及使用時的注意事項:
主要函式
-
陣列建立
np.array()
: 從列表或元組建立陣列。np.zeros()
: 建立全零陣列。np.ones()
: 建立全一陣列。np.arange()
: 建立等間隔的陣列。np.linspace()
: 建立指定數量的等間隔陣列。
-
陣列操作
np.reshape()
: 改變陣列的形狀。np.flatten()
: 將多維陣列展平為一維陣列。np.transpose()
: 轉置陣列。np.concatenate()
: 連線多個陣列。np.split()
: 分割陣列。
-
陣列運算
np.add()
,np.subtract()
,np.multiply()
,np.divide()
: 基本的算術運算。np.dot()
: 矩陣乘法。np.sum()
: 計算陣列的和。np.mean()
: 計算陣列的均值。np.std()
: 計算標準差。np.min()
,np.max()
: 計算最小值和最大值。
-
索引和切片
- 使用
[]
進行陣列索引。 - 使用
:
進行切片。 - 布林索引:透過條件生成布林陣列來篩選資料。
- 使用
-
線性代數
np.linalg.inv()
: 計算矩陣的逆。np.linalg.det()
: 計算矩陣的行列式。np.linalg.eig()
: 計算特徵值和特徵向量。
-
隨機數生成
np.random.rand()
: 生成均勻分佈的隨機數。np.random.randn()
: 生成標準正態分佈的隨機數。np.random.randint()
: 生成指定範圍內的隨機整數。
使用注意事項
-
陣列維度:確保在進行運算時,陣列的維度和形狀是相容的。使用
reshape()
和expand_dims()
可以幫助調整陣列的形狀。 -
資料型別:NumPy 陣列的元素型別是固定的,確保在建立陣列時指定合適的資料型別(如
dtype
),以避免意外的資料型別轉換。 -
記憶體管理:NumPy 陣列通常比 Python 列表佔用更少的記憶體,但在處理非常大的陣列時,仍需注意記憶體使用情況。使用
np.memmap()
可以處理超出記憶體限制的陣列。 -
廣播機制:NumPy 支援廣播(broadcasting),這允許不同形狀的陣列進行運算。理解廣播規則可以幫助你更有效地進行資料處理。
-
避免迴圈:儘量避免使用 Python 的 for 迴圈來處理 NumPy 陣列,使用向量化操作(如陣列運算)可以顯著提高效能。
-
隨機數種子:在進行隨機數生成時,如果需要可重複的結果,可以使用
np.random.seed()
設定隨機數種子。 -
使用文件:NumPy 有豐富的文件和示例,遇到問題時可以參考官方文件(NumPy Documentation)。
知識點
NumPy 是 Python 資料科學和機器學習領域中的核心庫之一,因此它經常成為面試中的話題。以下是一些關於 NumPy 的高頻面試題目以及相應的答案:
NumPy 中的 ndarray 是什麼?
ndarray 是 NumPy 中的一個核心物件,用於儲存同質型別的元素(如整數、浮點數等)。它是一個多維陣列,可以進行高效的元素級操作。
如何建立一個形狀為 (3, 4) 的 NumPy 陣列,並且用 0 填充?
答案:
import numpy as np
array = np.zeros((3, 4))
這將建立一個 3 行 4 列的陣列,所有元素都是 0。
如何獲取 NumPy 陣列的形狀?
import numpy as np
array = np.array([[1, 2, 3], [4, 5, 6]])
shape = array.shape
shape
屬性會返回一個元組,表示陣列的形狀。
如何改變 NumPy 陣列的形狀而不改變其資料?
import numpy as np
array = np.array([[1, 2, 3], [4, 5, 6]])
reshaped_array = array.reshape(3, 2)
這將把原陣列改變為 3 行 2 列的形狀。
如何將 Python 列表轉換為 NumPy 陣列?
使用 np.array() 函式可以將 Python 列表轉換為 NumPy 陣列。
如何計算 NumPy 陣列的均值、標準差和方差?
分別使用 np.mean()、np.std() 和 np.var() 函式。例如均值計算如下:
import numpy as np
array = np.array([1, 2, 3, 4, 5])
mean_value = np.mean(array)
np.mean()
函式可以計算陣列的均值。
如何在 NumPy 陣列中進行元素級別的操作?
NumPy 支援元素級別的操作,這意味著你可以對陣列中的每個元素應用算術運算或其他函式。例如:
import numpy as np
array1 = np.array([1, 2, 3])
array2 = np.array([4, 5, 6])
added_array = array1 + array2
這將返回一個新陣列 [5, 7, 9]
。
如何使用 NumPy 生成隨機數?
import numpy as np
random_array = np.random.rand(3, 4)
np.random.rand()
函式可以生成一個給定形狀的陣列,其元素是從 [0, 1) 區間內均勻分佈的隨機數。
如何檢查一個 NumPy 陣列是否包含任何 NaN 值?
import numpy as np
array = np.array([1, 2, np.nan, 4])
contains_nan = np.isnan(array)
np.isnan()
函式可以返回一個布林陣列,指示哪些位置是 NaN。
如何在 NumPy 陣列中進行條件篩選?
import numpy as np
array = np.array([1, 2, 3, 4, 5])
filtered_array = array[array > 2]
這將返回一個新陣列 [3, 4, 5]
,包含所有大於 2 的元素。
解釋 NumPy 中的 dtype
。
在 NumPy 中,dtype
是一個非常重要的概念,它代表資料型別(Data Type)。每個 NumPy 陣列都有一個與之相關的 dtype
,它指定了陣列中每個元素的資料型別。這有助於 NumPy 在記憶體中有效地儲存和處理資料。
dtype 的關鍵點
-
同質性:NumPy 陣列是同質的,這意味著陣列中的所有元素都必須是相同的資料型別。
dtype
確保了這一點。 -
記憶體效率:透過指定
dtype
,可以控制陣列在記憶體中的儲存方式,從而提高記憶體使用效率。 -
操作最佳化:不同的資料型別可能會影響陣列操作的效能。例如,整數和浮點數的操作速度可能不同。
-
型別轉換:如果建立陣列時沒有指定
dtype
,NumPy 會根據陣列元素的型別自動推斷dtype
。但是,如果需要,也可以顯式指定dtype
。 -
型別安全:在執行陣列操作時,確保所有元素的資料型別一致可以避免型別不匹配的錯誤。
常見的 NumPy 資料型別:
np.int32
:32位整數np.int64
:64位整數np.float32
:32位浮點數np.float64
:64位浮點數(雙精度)np.bool_
:布林型別(True 或 False)np.complex64
:複數,實部和虛部各佔32位np.complex128
:複數,實部和虛部各佔64位np.object
:Python 物件np.string_
:字串型別np.datetime64
:日期時間型別
示例
建立一個具有特定 dtype
的 NumPy 陣列:
import numpy as np
# 建立一個整數型別的陣列
int_array = np.array([1, 2, 3], dtype=np.int32)
print(int_array.dtype) # 輸出:int32
# 建立一個浮點數型別的陣列
float_array = np.array([1.0, 2.0, 3.0], dtype=np.float64)
print(float_array.dtype) # 輸出:float64
# 建立一個布林型別的陣列
bool_array = np.array([True, False, True], dtype=bool)
print(bool_array.dtype) # 輸出:bool
注意事項
- 當執行陣列操作時,如果涉及不同
dtype
的陣列,NumPy 通常會執行型別提升(type casting),以確保結果陣列的資料型別能夠容納所有可能的值。 - 顯式指定
dtype
可以幫助避免不必要的型別轉換,從而提高程式碼的效能和可讀性。 - 在處理大資料集時,合理選擇
dtype
可以顯著減少記憶體使用,提高處理速度。
dtype
是 NumPy 陣列的一個重要屬性,瞭解和正確使用 dtype
對於進行高效的數值計算至關重要。
為什麼 NumPy 比 Python 原生列表更快?
-
資料儲存:
- NumPy 陣列在記憶體中以連續塊的形式儲存資料,這意味著陣列中的元素是緊密排列的。這種連續儲存方式使得 CPU 快取能夠更有效地工作,因為當訪問陣列中的一個元素時,相鄰的元素也會被載入到快取中。
- Python 原生列表儲存的是物件的引用,這些物件可能散佈在記憶體的任何地方,這導致了更多的記憶體訪問延遲。
-
資料型別:
- NumPy 陣列中的元素都是同質的,這意味著它們具有相同的資料型別,這使得 NumPy 可以最佳化記憶體使用和計算操作。
- Python 列表可以包含不同型別的元素,這增加了記憶體使用的複雜性。
-
操作最佳化:
- NumPy 是用 C 語言編寫的,它的陣列操作是用低階語言實現的,這使得操作非常快速和高效。
- Python 列表的操作是用 Python 這門高階語言實現的,這通常涉及到更多的函式呼叫和直譯器開銷。
-
向量化操作:
- NumPy 支援向量化操作,這意味著可以一次性對陣列的多個元素執行操作,而不需要使用迴圈。這些操作是用 C 語言編寫的,可以被編譯成機器程式碼,從而實現高效能。
- Python 列表通常需要使用迴圈來迭代元素,這增加了額外的開銷。
-
廣播機制:
- NumPy 的廣播機制允許不同形狀的陣列在算術操作中協同工作,而不需要顯式地進行元素級別的迴圈。
-
演算法實現:
- NumPy 的演算法實現通常更加最佳化,因為它們是專門為數值計算設計的。
-
並行處理:
- 對於某些操作,NumPy 可以利用並行處理來進一步提高效能,尤其是在多核處理器上。
-
記憶體管理:
- NumPy 在建立陣列時,會明確指定資料型別和大小,這有助於減少記憶體分配和回收的開銷。
-
快取效率:
- 由於 NumPy 陣列的連續記憶體分配,現代 CPU 的快取機制能夠更有效地工作,因為資料訪問模式更加區域性化。
-
避免Python直譯器開銷:
- Python 列表的操作需要 Python 直譯器的介入,而 NumPy 操作很多都是直接在底層執行,避免瞭直譯器的開銷。
如何最佳化 NumPy 程式碼的效能?
答案:使用向量化操作而不是迴圈,避免不必要地複製資料,使用適當的資料型別,以及並行處理(如使用 np.dot 替代 for 迴圈計算點積)。
解釋 NumPy 中的廣播機制。
NumPy 中的廣播(Broadcasting)機制是一種強大的功能,它允許不同形狀的陣列在數學運算中協同工作,而不需要顯式地匹配它們的形狀。廣播機制遵循以下規則:
-
維度對齊:從左到右比較兩個陣列的維度,確保它們的維度是對齊的。這意味著較短陣列的前面會填充1(例如,
(3,)
被視為(1, 3)
)。 -
維度擴充套件:如果兩個陣列在某個維度的大小不一致,那麼較小陣列的形狀會在該維度上被擴充套件以匹配較大陣列。這是透過複製較小陣列的維度值來實現的。
-
形狀比較:從尾部維度(最右邊的維度)開始,逐個維度比較兩個陣列的形狀。如果兩個維度相等,或其中一個維度為1,則認為它們是相容的。
-
複製擴充套件:如果一個陣列的維度大小為1,而另一個陣列的維度大小大於1,則將維度大小為1的陣列複製擴充套件到與另一個陣列相同的維度大小。
-
廣播結果:如果兩個陣列在所有維度上都相容,那麼它們就可以進行廣播,從而形成一個新的陣列形狀,用於計算。
例如:
import numpy as np
# 建立兩個陣列
a = np.array([1, 2, 3]) # 形狀為 (3,)
b = np.array([[1], [2], [3]]) # 形狀為 (3, 1)
# 廣播相加
c = a + b # 結果是一個形狀為 (3, 3) 的陣列
print(c)
# 輸出:
# [[2 2 2]
# [3 3 3]
# [4 4 4]]
在這個例子中,a
的形狀是 (3,)
,b
的形狀是 (3, 1)
。根據廣播規則,a
被擴充套件到 (3, 3)
,b
也被擴充套件到 (3, 3)
,然後進行逐元素相加。
廣播機制使得 NumPy 在執行元素級操作時非常高效,因為它避免了不必要的陣列複製和迴圈。然而,它也有潛在的缺點,比如有時可能會導致意外的結果,特別是在陣列形狀複雜或操作不明確時。因此,理解廣播機制對於編寫清晰、高效的 NumPy 程式碼至關重要。
在機器學習中,如何使用 NumPy 進行特徵縮放?
在機器學習中,特徵縮放是一種重要的預處理步驟,它有助於改善模型的效能和收斂速度。特徵縮放包括多種技術,其中最常見的是最小-最大歸一化(Min-Max Scaling)和標準化(Standardization)。以下是如何使用 NumPy 進行這兩種特徵縮放的方法:
最小-最大歸一化(Min-Max Scaling)
最小-最大歸一化將特徵縮放到一個指定的範圍,通常是 [0, 1]。這種方法對於保持資料中的特徵比例很有用。
import numpy as np
# 假設 X 是一個形狀為 (n_samples, n_features) 的資料陣列
X = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
# 計算每個特徵的最小值和最大值
X_min = X.min(axis=0)
X_max = X.max(axis=0)
# 執行最小-最大歸一化
X_scaled = (X - X_min) / (X_max - X_min)
print(X_scaled)
標準化(Standardization)
標準化(也稱為 Z-score 歸一化)將特徵縮放,使得它們的均值為 0,標準差為 1。這有助於確保不同特徵的尺度不會影響模型的最佳化過程。
# 假設 X 是一個形狀為 (n_samples, n_features) 的資料陣列
X = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
# 計算每個特徵的均值和標準差
X_mean = X.mean(axis=0)
X_std = X.std(axis=0)
# 執行標準化
X_standardized = (X - X_mean) / X_std
print(X_standardized)
注意事項
-
避免資料洩露:在訓練集上計算用於縮放的引數(如最小值、最大值、均值和標準差)時,應確保不要使用測試集或驗證集的資料,這被稱為資料洩露。
-
儲存縮放引數:在訓練集上訓練模型後,應該儲存用於特徵縮放的引數(最小值、最大值、均值和標準差),以便在測試集或生產環境中對新資料進行相同的縮放。
-
選擇縮放方法:不同的模型可能對特徵縮放的敏感度不同。例如,距離基模型(如 K-最近鄰和 SVM)通常會從縮放中受益,而樹基模型(如決策樹和隨機森林)通常不需要特徵縮放。
-
處理缺失值:在進行特徵縮放之前,應該處理資料中的缺失值,因為它們可能會影響均值和標準差的計算。
使用 NumPy 進行特徵縮放是直接且高效的,但請注意,NumPy 不提供內建的函式來自動應用這些縮放技術。在實踐中,scikit-learn
庫提供了更高階的特徵縮放方法,如 MinMaxScaler
和 StandardScaler
,它們可以更方便地處理這些問題。
如何使用 NumPy 進行主成分分析(PCA)?
步驟 1: 準備資料
首先,你需要一個形狀為 (n_samples, n_features)
的資料陣列。
import numpy as np
# 示例資料
X = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
步驟 2: 資料標準化
PCA 對資料的尺度非常敏感,因此通常需要先標準化資料。
X_centered = X - np.mean(X, axis=0)
X_std = np.std(X_centered, axis=0)
X_normalized = X_centered / X_std
步驟 3: 計算協方差矩陣
協方差矩陣用於找到資料的主成分。
cov_matrix = np.cov(X_normalized.T)
步驟 4: 計算特徵值和特徵向量
特徵值和特徵向量表示了資料的主成分方向。
eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)
步驟 5: 選擇主成分
選擇最大的幾個特徵值對應的特徵向量作為主成分。
# 按特徵值大小降序排序特徵向量
sorted_index = np.argsort(eigenvalues)[::-1]
principal_components = eigenvectors[:, sorted_index[:n_components]]
其中 n_components
是你想要保留的成分數量。
步驟 6: 轉換資料
將原始資料投影到選定的主成分上。
X_pca = np.dot(X_normalized, principal_components)
使用 X_pca
可以得到降維後的資料。
NumPy PCA 示例程式碼
import numpy as np
# 示例資料
X = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
# 標準化資料
X_centered = X - np.mean(X, axis=0)
X_std = np.std(X_centered, axis=0)
X_normalized = X_centered / X_std
# 計算協方差矩陣
cov_matrix = np.cov(X_normalized.T)
# 計算特徵值和特徵向量
eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)
# 按特徵值大小降序排序特徵向量
sorted_index = np.argsort(eigenvalues)[::-1]
n_components = 2 # 選擇前兩個主成分
principal_components = eigenvectors[:, sorted_index[:n_components]]
# 轉換資料
X_pca = np.dot(X_normalized, principal_components)
print(X_pca)
注意事項
- 資料標準化是 PCA 的重要步驟,確保每個特徵具有單位方差。
- 在實踐中,通常使用
scikit-learn
的 PCA 實現,因為它更高效、更方便,並且包含了更多的功能,如自動選擇元件數量等。 - NumPy 的 PCA 實現沒有考慮奇異值分解(SVD),這在處理具有更多特徵的資料時可能更有效。
使用 scikit-learn
的 PCA 實現非常簡單:
from sklearn.decomposition import PCA
# 示例資料
X = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
# 初始化 PCA,n_components 為需要保留的成分數量
pca = PCA(n_components=2)
# 對資料進行擬合和轉換
X_pca = pca.fit_transform(X)
print(X_pca)
這種方法更加簡潔,且 scikit-learn
會自動處理資料標準化和奇異值分解(SVD)。