python3 numpy的一些小知識點

Kevinarcsin001發表於2024-09-24

簡介

一個用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 在資料處理時常用的主要函式,以及使用時的注意事項:

主要函式

  1. 陣列建立

    • np.array(): 從列表或元組建立陣列。
    • np.zeros(): 建立全零陣列。
    • np.ones(): 建立全一陣列。
    • np.arange(): 建立等間隔的陣列。
    • np.linspace(): 建立指定數量的等間隔陣列。
  2. 陣列操作

    • np.reshape(): 改變陣列的形狀。
    • np.flatten(): 將多維陣列展平為一維陣列。
    • np.transpose(): 轉置陣列。
    • np.concatenate(): 連線多個陣列。
    • np.split(): 分割陣列。
  3. 陣列運算

    • np.add(), np.subtract(), np.multiply(), np.divide(): 基本的算術運算。
    • np.dot(): 矩陣乘法。
    • np.sum(): 計算陣列的和。
    • np.mean(): 計算陣列的均值。
    • np.std(): 計算標準差。
    • np.min(), np.max(): 計算最小值和最大值。
  4. 索引和切片

    • 使用 [] 進行陣列索引。
    • 使用 : 進行切片。
    • 布林索引:透過條件生成布林陣列來篩選資料。
  5. 線性代數

    • np.linalg.inv(): 計算矩陣的逆。
    • np.linalg.det(): 計算矩陣的行列式。
    • np.linalg.eig(): 計算特徵值和特徵向量。
  6. 隨機數生成

    • np.random.rand(): 生成均勻分佈的隨機數。
    • np.random.randn(): 生成標準正態分佈的隨機數。
    • np.random.randint(): 生成指定範圍內的隨機整數。

使用注意事項

  1. 陣列維度:確保在進行運算時,陣列的維度和形狀是相容的。使用 reshape()expand_dims() 可以幫助調整陣列的形狀。

  2. 資料型別:NumPy 陣列的元素型別是固定的,確保在建立陣列時指定合適的資料型別(如 dtype),以避免意外的資料型別轉換。

  3. 記憶體管理:NumPy 陣列通常比 Python 列表佔用更少的記憶體,但在處理非常大的陣列時,仍需注意記憶體使用情況。使用 np.memmap() 可以處理超出記憶體限制的陣列。

  4. 廣播機制:NumPy 支援廣播(broadcasting),這允許不同形狀的陣列進行運算。理解廣播規則可以幫助你更有效地進行資料處理。

  5. 避免迴圈:儘量避免使用 Python 的 for 迴圈來處理 NumPy 陣列,使用向量化操作(如陣列運算)可以顯著提高效能。

  6. 隨機數種子:在進行隨機數生成時,如果需要可重複的結果,可以使用 np.random.seed() 設定隨機數種子。

  7. 使用文件: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 的關鍵點

  1. 同質性:NumPy 陣列是同質的,這意味著陣列中的所有元素都必須是相同的資料型別。dtype 確保了這一點。

  2. 記憶體效率:透過指定 dtype,可以控制陣列在記憶體中的儲存方式,從而提高記憶體使用效率。

  3. 操作最佳化:不同的資料型別可能會影響陣列操作的效能。例如,整數和浮點數的操作速度可能不同。

  4. 型別轉換:如果建立陣列時沒有指定 dtype,NumPy 會根據陣列元素的型別自動推斷 dtype。但是,如果需要,也可以顯式指定 dtype

  5. 型別安全:在執行陣列操作時,確保所有元素的資料型別一致可以避免型別不匹配的錯誤。

常見的 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 原生列表更快?

  1. 資料儲存

    • NumPy 陣列在記憶體中以連續塊的形式儲存資料,這意味著陣列中的元素是緊密排列的。這種連續儲存方式使得 CPU 快取能夠更有效地工作,因為當訪問陣列中的一個元素時,相鄰的元素也會被載入到快取中。
    • Python 原生列表儲存的是物件的引用,這些物件可能散佈在記憶體的任何地方,這導致了更多的記憶體訪問延遲。
  2. 資料型別

    • NumPy 陣列中的元素都是同質的,這意味著它們具有相同的資料型別,這使得 NumPy 可以最佳化記憶體使用和計算操作。
    • Python 列表可以包含不同型別的元素,這增加了記憶體使用的複雜性。
  3. 操作最佳化

    • NumPy 是用 C 語言編寫的,它的陣列操作是用低階語言實現的,這使得操作非常快速和高效。
    • Python 列表的操作是用 Python 這門高階語言實現的,這通常涉及到更多的函式呼叫和直譯器開銷。
  4. 向量化操作

    • NumPy 支援向量化操作,這意味著可以一次性對陣列的多個元素執行操作,而不需要使用迴圈。這些操作是用 C 語言編寫的,可以被編譯成機器程式碼,從而實現高效能。
    • Python 列表通常需要使用迴圈來迭代元素,這增加了額外的開銷。
  5. 廣播機制

    • NumPy 的廣播機制允許不同形狀的陣列在算術操作中協同工作,而不需要顯式地進行元素級別的迴圈。
  6. 演算法實現

    • NumPy 的演算法實現通常更加最佳化,因為它們是專門為數值計算設計的。
  7. 並行處理

    • 對於某些操作,NumPy 可以利用並行處理來進一步提高效能,尤其是在多核處理器上。
  8. 記憶體管理

    • NumPy 在建立陣列時,會明確指定資料型別和大小,這有助於減少記憶體分配和回收的開銷。
  9. 快取效率

    • 由於 NumPy 陣列的連續記憶體分配,現代 CPU 的快取機制能夠更有效地工作,因為資料訪問模式更加區域性化。
  10. 避免Python直譯器開銷

    • Python 列表的操作需要 Python 直譯器的介入,而 NumPy 操作很多都是直接在底層執行,避免瞭直譯器的開銷。

如何最佳化 NumPy 程式碼的效能?

答案:使用向量化操作而不是迴圈,避免不必要地複製資料,使用適當的資料型別,以及並行處理(如使用 np.dot 替代 for 迴圈計算點積)。

解釋 NumPy 中的廣播機制。

NumPy 中的廣播(Broadcasting)機制是一種強大的功能,它允許不同形狀的陣列在數學運算中協同工作,而不需要顯式地匹配它們的形狀。廣播機制遵循以下規則:

  1. 維度對齊:從左到右比較兩個陣列的維度,確保它們的維度是對齊的。這意味著較短陣列的前面會填充1(例如,(3,) 被視為 (1, 3))。

  2. 維度擴充套件:如果兩個陣列在某個維度的大小不一致,那麼較小陣列的形狀會在該維度上被擴充套件以匹配較大陣列。這是透過複製較小陣列的維度值來實現的。

  3. 形狀比較:從尾部維度(最右邊的維度)開始,逐個維度比較兩個陣列的形狀。如果兩個維度相等,或其中一個維度為1,則認為它們是相容的。

  4. 複製擴充套件:如果一個陣列的維度大小為1,而另一個陣列的維度大小大於1,則將維度大小為1的陣列複製擴充套件到與另一個陣列相同的維度大小。

  5. 廣播結果:如果兩個陣列在所有維度上都相容,那麼它們就可以進行廣播,從而形成一個新的陣列形狀,用於計算。

例如:

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)

注意事項

  1. 避免資料洩露:在訓練集上計算用於縮放的引數(如最小值、最大值、均值和標準差)時,應確保不要使用測試集或驗證集的資料,這被稱為資料洩露。

  2. 儲存縮放引數:在訓練集上訓練模型後,應該儲存用於特徵縮放的引數(最小值、最大值、均值和標準差),以便在測試集或生產環境中對新資料進行相同的縮放。

  3. 選擇縮放方法:不同的模型可能對特徵縮放的敏感度不同。例如,距離基模型(如 K-最近鄰和 SVM)通常會從縮放中受益,而樹基模型(如決策樹和隨機森林)通常不需要特徵縮放。

  4. 處理缺失值:在進行特徵縮放之前,應該處理資料中的缺失值,因為它們可能會影響均值和標準差的計算。

使用 NumPy 進行特徵縮放是直接且高效的,但請注意,NumPy 不提供內建的函式來自動應用這些縮放技術。在實踐中,scikit-learn 庫提供了更高階的特徵縮放方法,如 MinMaxScalerStandardScaler,它們可以更方便地處理這些問題。

如何使用 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)。

如果有錯誤的地方歡迎大佬批評指正,謝謝

相關文章