返回目錄
A
數據洞察:從基礎到實踐的資料科學全書 - 第 3 章
第 3 章:資料前處理的藝術與科學
發布於 2026-02-28 02:30
# 第 3 章:資料前處理的藝術與科學
> **為什麼前處理如此重要?**\n資料科學的成功往往取決於「乾淨」與「結構化」的輸入。即使是最先進的機器學習模型,也無法在缺失值、異常值或不一致的編碼面前保持良好表現。這一章將帶你從實際案例出發,學習如何將雜亂的資料轉換為機器學習友好的結構。
## 3.1 前言
- **前處理**:資料從收集到模型訓練的「橋樑」。
- 目標:降低噪音、提升模型泛化、加速迭代。\n
> **案例啟示**:在 2024 年的「客戶流失預測」專案中,缺失值佔 12% 的特徵若不處理,模型召回率下降 7%。
## 3.2 缺失值處理
| 方法 | 適用情境 | 代碼範例 |
|------|----------|----------|
| 刪除 | 缺失值比例極低,且不會引起樣本偏差 | python
import pandas as pd
df = df.dropna(subset=['age', 'salary'])
|
| 代入均值/中位數 | 數值型特徵,缺失分布大致對稱 | python
from sklearn.impute import SimpleImputer
imp = SimpleImputer(strategy='median')
df['age'] = imp.fit_transform(df[['age']])
|
| 代入常數 / 最頻值 | 分類特徵,缺失代表「未知」 | python
imp = SimpleImputer(strategy='most_frequent')
df['gender'] = imp.fit_transform(df[['gender']])
|
| 迭代插補 | 變數間高度相關,需保持結構 | python
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
imp = IterativeImputer(random_state=0)
df = pd.DataFrame(imp.fit_transform(df), columns=df.columns)
|
> **小技巧**:在 `pandas` 中使用 `df.isna().sum()` 先統計缺失分布,視情況選擇方法。
## 3.3 標準化與歸一化
| 方法 | 效果 | 適用場景 |
|------|------|----------|
| Z‑Score 標準化 | 平均值 0,標準差 1 | 需要距離度量的模型(SVM、KNN) |
| Min‑Max 歸一化 | 將值壓縮至 [0,1] | 對於 Neural Network 的輸入層 |
| Robust Scaling | 以 IQR 為基準 | 異常值較多的資料 |
python
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(df[['age', 'salary']])
> **實務提醒**:將縮放器納入 `Pipeline`,確保訓練/測試的統一流程。
## 3.4 類別編碼技巧
| 編碼 | 原理 | 何時使用 |
|------|------|----------|
| One‑Hot | 為每類別建立二進制向量 | 類別無序(例如顏色) |
| Ordinal | 為類別賦予順序 | 有明確排序(例如教育程度) |
| Target Encoding | 用目標變量的平均值替換 | 避免高維度、稀疏特徵 |
python
from sklearn.preprocessing import OneHotEncoder
enc = OneHotEncoder(sparse=False)
encoded = enc.fit_transform(df[['city']])
> **警示**:Target Encoding 需做 K‑Fold 交叉驗證,防止資訊洩漏。
## 3.5 特徵工程與篩選
1. **派生特徵**:組合、交互、數學轉換。
- `df['age_group'] = pd.cut(df['age'], bins=[0,20,40,60,100], labels=['0-20','20-40','40-60','60+'])`
2. **特徵重要性排序**:使用 `RandomForestRegressor` 或 `XGBoost` 的 `feature_importances_`。
3. **遞迴特徵刪除 (RFE)**:逐步移除低重要性特徵。
4. **主成份分析 (PCA)**:降維保留 95% 變異。
> **實例**:在房價預測中,將 `sqft_living` 與 `sqft_above` 組合成 `total_sqft`,可顯著提升模型 R²。
## 3.6 數據質量檢查
- **重複資料**:`df.duplicated().sum()`。
- **不一致值**:字元大小寫、前後空白,使用 `str.strip()`、`str.lower()`。
- **邏輯檢查**:例如 `age` 不能為負,`birth_year` 與 `current_year` 的差值合理。
- **離群值檢測**:箱型圖、IQR 方法、Z‑Score 超過 3。
python
q1 = df['salary'].quantile(0.25)
q3 = df['salary'].quantile(0.75)
iqr = q3 - q1
lower, upper = q1 - 1.5 * iqr, q3 + 1.5 * iqr
outliers = df[(df['salary'] < lower) | (df['salary'] > upper)]
> **記錄與追蹤**:使用 `data.dvc` 或 `git lfs` 版本化資料,保證可回溯。
## 3.7 建立可重複流程
- **使用 `Pipeline`**:將缺失處理、標準化、編碼串接。
- **保存**:`joblib.dump(pipeline, 'pipeline.pkl')`,部署時直接 `joblib.load()`。
- **測試**:分離測試集,確保資料流不混入訓練資訊。
- **日志**:`logging` 模組追蹤前處理步驟與參數。
python
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
numeric_features = ['age', 'salary']
numeric_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='median')),
('scaler', StandardScaler()),
])
categorical_features = ['gender', 'city']
categorical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='most_frequent')),
('onehot', OneHotEncoder(handle_unknown='ignore')),
])
preprocessor = ColumnTransformer(
transformers=[
('num', numeric_transformer, numeric_features),
('cat', categorical_transformer, categorical_features),
])
pipeline = Pipeline(steps=[('preprocessor', preprocessor)])
> **部署**:將 pipeline 包裝成 `setup.py` 或 `pyproject.toml`,轉成 Python package,確保團隊協作一致。
## 3.8 小結
- **前處理** 不是「雜項」工作,而是構建堅實基礎的關鍵環節。\n- **缺失值** 需要根據資料特性靈活處理。\n- **標準化** 與 **編碼** 要與模型選型相匹配。\n- **特徵工程** 既是創造性工作,也是系統化的迭代。\n- **數據質量檢查** 是防止後續模型失效的第一道防線。\n- **可重複流程** 的建立,保障團隊從實驗到部署的順暢與可追溯。
> **下一步**:第 4 章將深入機器學習算法,從線性模型到樹模型,並在前處理基礎上進行模型訓練、評估與調參。