在機器學習中,數據標準化(Standardization)
是一個非常重要的步驟。sklearn.preprocessing.StandardScaler
是一個專門用於標準化數據的工具,
它可以讓模型訓練更加高效,
並提升模型的魯棒性(robustness,抗干擾能力)。
這篇文章將分步教你如何使用 StandardScaler
,
並解釋如何保存和加載處理器以便在實際應用中重複使用。
1. 為什麼要標準化數據?
當數據的數值範圍相差很大時,
不同特徵對模型的影響可能會失衡。例如:
- 特徵 A 的數值範圍是 1 到 1000。
- 特徵 B 的數值範圍是 0.1 到 1。
在這種情況下,特徵 A 的數值範圍遠大於特徵 B,
模型可能會更傾向於依賴特徵 A,導致訓練結果不準確。
標準化的作用:
- 平衡特徵影響:將數據轉換為均值為 0,標準差為 1 的分佈。
- 加速模型訓練:讓梯度下降算法更快收斂。
- 提升模型效果:適合對數值範圍敏感的算法(如 SVM、KNN、線性迴歸等)。
2. 什麼是 StandardScaler
?
StandardScaler
是 scikit-learn
提供的數據標準化工具,
根據以下公式對數據進行轉換:
- μ 是特徵的均值(Mean)。
- σ 是特徵的標準差(Standard Deviation)。
3. 基本使用:對數據進行標準化
步驟 1:準備數據
我們先準備一個簡單的數據集:
注意:X是一個2D數據,即使第二維長度僅有1,StandardScaler
不支持 1D 數據,
因為它需要明確的數據結構(樣本數 × 特徵數)。
步驟 2:使用 StandardScaler
標準化數據
解釋:
- 標準化後的數據具有以下特性:
- 均值為 0。
- 標準差為 1。
步驟 3:還原數據
當我們需要將標準化後的數據還原成原始數據時,
可以使用 inverse_transform
方法:
4. 使用 pandas 進行批量標準化
在實際項目中,我們通常會處理多個特徵的數據集(例如 DataFrame)。
以下是如何使用 StandardScaler
對多列數據進行標準化的範例:
5. 保存和加載 StandardScaler
:使用 joblib
在實際應用中,我們通常需要將訓練好的處理器保存起來,
以便後續使用(例如處理測試數據或部署模型)。
這時可以使用 joblib
來保存和加載 StandardScaler
。
保存 Scaler
import joblib
# 保存 Scaler 到文件
joblib.dump(scaler, "scaler.joblib")
print("Scaler 已保存到文件:scaler.joblib")
加載 Scaler
# 從文件加載 Scaler
loaded_scaler = joblib.load("scaler.joblib")
# 使用加載的 Scaler 進行標準化
X_test = np.array([[4.0]])
X_test_scaled = loaded_scaler.transform(X_test)
print("測試數據標準化後:", X_test_scaled)
6. 如何處理目標值(y)的標準化?
如果我們的目標值(如迴歸任務中的 y
)也需要標準化,
可以同樣使用 StandardScaler
:
7. 總結
StandardScaler
的核心功能
- 標準化數據:將數據轉換為均值為 0,標準差為 1 的分佈。
- 還原數據:可以將標準化後的數據還原為原始數據。
典型使用流程
- 初始化和訓練 Scaler:
scaler.fit(X)
。 - 標準化數據:
scaler.transform(X)
。 - 還原數據:
scaler.inverse_transform(X_scaled)
。 - 保存和加載 Scaler:用
joblib.dump()
保存,用joblib.load()
加載。
推薦hahow線上學習python: https://igrape.net/30afN
StandardScaler
無法直接用於 1D 數據,
這是因為它期望輸入數據是 2D 數據(如 (樣本數, 特徵數)
的形狀)。
即使你的數據只有一個特徵(如一列數據),
也需要將其展開為 2D 格式,否則會導致錯誤。
為什麼 StandardScaler
需要 2D 數據?
StandardScaler
是設計用來處理 多個樣本和多個特徵 的工具:
- 每一列(特徵)會單獨計算均值和標準差。
- 每一行(樣本)代表一個數據點。
當你傳入 1D 數據(如 [1, 2, 3]
),StandardScaler
無法分辨出數據的結構:
它不知道這是 3 個樣本的單column數據,
還是 1 個樣本的 3 個特徵。
如何解決?
如果你的數據是 1D 的,
可以使用 reshape(-1, 1)
將其轉換為 2D 格式,
這樣 StandardScaler
就能正確處理。
範例:1D 數據會報錯
# %%
from sklearn.preprocessing import StandardScaler
# 1D 數據
X = [1, 2, 3] # 只有一個特徵
# 初始化 StandardScaler
scaler = StandardScaler()
# 嘗試標準化
X_scaled = scaler.fit_transform(X) # 這會報錯
錯誤信息:
ValueError: Expected 2D array, got 1D array instead: array=[1. 2. 3.].
Reshape your data either using
array.reshape(-1, 1) if your data has a single feature or
array.reshape(1, -1) if it contains a single sample.
正確方法:將 1D 數據轉換為 2D
為什麼 .reshape(-1, 1)
可以解決問題?
reshape(-1, 1)
的意思是將數據重塑為 2D 數組,其中:-1
會自動計算rows(樣本數)。1
表示只有一欄特徵。
例如:
np.array([1, 2, 3]).reshape(-1, 1)
# 變成:
array([[1],
[2],
[3]])
這樣,StandardScaler
就能理解這是 3 個樣本的單column數據。
為什麼 StandardScaler
不直接支持 1D 數據?
StandardScaler
的設計目的是為了處理多列特徵(多維數據),
用於機器學習的典型場景。
對於 1D 數據,scikit-learn
的開發者選擇了更嚴格的接口設計,
強制用戶顯式提供數據的結構,來避免潛在的誤用。
例如,如果允許 1D 數據:
[1, 2, 3]
可能被誤解為 1 個樣本的 3 個特徵,而不是 3 個樣本的單個特徵。
通過要求 2D 格式,scikit-learn
可以清楚地區分數據的結構(行為樣本,列為特徵)。
使用 1D 數據的替代方法
如果你確實只需要對 1D 數據進行標準化,
並且不想轉換為 2D,完全可以用 numpy
手動計算均值和標準差:
總結
StandardScaler
不支持 1D 數據,因為它需要明確的數據結構(樣本數 × 特徵數)。- 解決方法:
- 將 1D 數據轉換為 2D,使用
.reshape(-1, 1)
。 - 或者直接用
numpy
手動標準化。
- 將 1D 數據轉換為 2D,使用
- 嚴格要求 2D 格式是為了避免數據結構模糊的問題,提高接口的清晰性和穩定性。
部分code:
正確的標準化數據步驟:避免數據洩漏
在機器學習或深度學習中,數據標準化是非常重要的一步。
本文將解釋如何正確進行訓練集和測試集的標準化,
並說明每個步驟背後的原因。
1. 背景與問題
假設我們有以下數據集:
- 訓練集 X_train:用於訓練模型。
- 測試集 X_test:用於驗證模型的性能。
當我們對數據進行標準化時,必須遵循以下原則:
- 訓練集:使用
fit_transform()
,計算均值和標準差,並對數據進行轉換。 - 測試集:使用
transform()
,直接使用從訓練集計算的均值和標準差進行轉換。
2. 為什麼這麼做?
2.1 訓練集使用 fit_transform()
fit
:計算訓練集每個特徵的均值和標準差。transform
:使用這些均值和標準差將數據縮放為標準化格式(均值為 0,標準差為 1)。
2.2 測試集使用 transform()
- 測試集的數據必須用訓練集的統計量(均值和標準差)進行縮放,
這模擬了模型在真實場景中處理「未見數據」的情況。
2.3 如果對測試集使用 fit_transform()
會怎麼樣?
- 數據洩漏 (Data Leakage):測試集的統計量影響了模型的訓練過程,
這相當於提前讓模型「偷看」了測試數據。 - 不符合實際情況:在真實應用中,模型接觸的數據是未知的,
因此測試集應該始終使用訓練集的統計量進行轉換。
3. 正確的數據標準化步驟
以下是正確的實現方式,基於 StandardScaler
和 numpy
:
範例程式碼
# %%
from sklearn.preprocessing import StandardScaler
import numpy as np
# 假設訓練集和測試集
X_train = np.random.rand(604, 44) # 訓練數據
X_test = np.random.rand(260, 44) # 測試數據
# 初始化標準化器
scaler_X = StandardScaler()
# 對訓練集進行標準化
X_train_scaled = scaler_X.fit_transform(X_train)
# 使用訓練集的均值和標準差,對測試集進行標準化
X_test_scaled = scaler_X.transform(X_test)
print("訓練集標準化後的形狀:", X_train_scaled.shape)
print("測試集標準化後的形狀:", X_test_scaled.shape)
輸出結果:
4. 適用於目標值(y)的標準化
對於迴歸任務,我們也可以對目標值 y進行標準化。以下是範例:
6. 常見錯誤與解決方法
- 未先使用
fit_transform()
就直接transform()
- 錯誤提示:
NotFittedError
。 - 解決方法:確保在使用
transform()
之前,先對訓練集使用fit_transform()
。
- 錯誤提示:
- 對測試集使用了
fit_transform()
- 問題:導致數據洩漏。
- 解決方法:測試集僅使用
transform()
。
- 數據格式錯誤
- 問題:Keras 模型需要 numpy 陣列,而
pandas
DataFrame 可能未轉換。 - 解決方法:使用
.values
或.to_numpy()
將 DataFrame 轉為 numpy 陣列。
- 問題:Keras 模型需要 numpy 陣列,而
7. 總結
正確的標準化步驟
- 訓練集:使用
fit_transform()
。 - 測試集:使用
transform()
。 - 避免數據洩漏:測試集始終使用訓練集的統計量。
為什麼重要?
- 保證模型的泛化能力(對未見數據的表現)。
- 避免不必要的數據洩漏,模擬實際應用場景。
關於目標值
- 對目標值 y 的標準化同樣需要遵守這些原則。
這些步驟不僅適用於 StandardScaler
,
還適用於其他縮放器(如 MinMaxScaler
)。
推薦hahow線上學習python: https://igrape.net/30afN