返回目錄
A
數據科學:從原始資料到策略洞察 - 第 5 章
第五章:實戰特徵工程與 MLflow 實驗管理
發布於 2026-02-25 11:38
# 第五章:實戰特徵工程與 MLflow 實驗管理
> **核心訊息**:在真實競賽環境中,特徵工程往往決定了模型表現的差距。透過可重現的實驗追蹤與版本控制,才能在迭代中保持一致性與可解釋性。
---
## 5.1 目標與數據集概覽
Kaggle 的 *House‑Price Advanced Regression Models* 是一個典型的房價預測競賽,包含 81 款特徵(數值、分類、日期、文本)和 1460 筆訓練樣本。目標是預測每棟住宅的銷售價格(`SalePrice`)。本章的重點不在於最終分數,而在於:
1. **可重現性**:每一次實驗都可追蹤、回溯。
2. **特徵品質提升**:從業務角度設計、篩選、轉換特徵。
3. **可解釋性**:使用 SHAP、Permutation Importance 來說明模型決策。
> **開放式思考**:我們不只是套用標準流程,而是把業務知識與統計方法交互驗證,探索未知的特徵組合。
---
## 5.2 數據準備與初步探索
python
import pandas as pd
from pathlib import Path
DATA_PATH = Path('data')
train = pd.read_csv(DATA_PATH / 'train.csv')
test = pd.read_csv(DATA_PATH / 'test.csv')
print(train.shape, test.shape)
print(train.head())
- **缺失值**:使用 `train.isna().sum()` 觀察缺失比例,並針對高缺失特徵進行決策(刪除或填補)。
- **離群值**:透過箱型圖、z‑score 篩選,特別關注價格與房屋面積的關係。
---
## 5.3 業務驅動的衍生特徵
| 類型 | 具體實作 | 目的 |
|------|----------|------|
| **組合特徵** | `TotalSF = TotalBsmtSF + 1stFlrSF + 2ndFlrSF` | 反映房屋實際使用面積 |
| **比例特徵** | `PricePerSqft = SalePrice / TotalSF` | 測試價格相對於面積的合理性 |
| **時間特徵** | `YearsSinceBuilt = YrSold - YearBuilt` | 房屋年齡 |
| **類別映射** | `MSZoning` → 數值序列 | 讓分類特徵可直接輸入線性模型 |
> **開放式實驗**:同時保留原始特徵與衍生特徵,後續透過 Feature Importance 排除冗餘。 |
---
## 5.4 相關性分析、VIF 與特徵篩選
python
from statsmodels.stats.outliers_influence import variance_inflation_factor
from sklearn.feature_selection import VarianceThreshold
numeric_cols = train.select_dtypes(include='number').columns.tolist()
# 1. 相關性矩陣
corr_matrix = train[numeric_cols].corr().abs()
# 2. VIF
X = train[numeric_cols].drop('SalePrice', axis=1)
vif = pd.DataFrame({'Feature': X.columns, 'VIF': [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]})
print(vif.sort_values('VIF', ascending=False).head())
- **VIF > 5** 的特徵標示高度共線,選擇刪除或合併。
- **VarianceThreshold** 用於剔除變異量極低的特徵。
---
## 5.5 轉換與標準化
- **數值標準化**:`StandardScaler`(零均值、單位方差)
- **類別編碼**:`OneHotEncoder` + `handle_unknown='ignore'`
- **非線性轉換**:對偏態分布採用 `np.log1p` 或 `BoxCox`。
python
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
numeric_features = X.select_dtypes(include=['int64', 'float64']).columns
categorical_features = X.select_dtypes(include=['object', 'category']).columns
preprocess = ColumnTransformer([
('num', StandardScaler(), numeric_features),
('cat', OneHotEncoder(handle_unknown='ignore'), categorical_features)
])
---
## 5.6 建模與驗證策略
- **基線模型**:線性回歸、Lasso、Ridge。
- **複雜模型**:Gradient Boosting、XGBoost、LightGBM。
- **交叉驗證**:`KFold` 或 `StratifiedKFold`,使用 `Mean Absolute Error (MAE)` 作為評估指標。
python
from sklearn.model_selection import cross_val_score
from sklearn.pipeline import Pipeline
from sklearn.metrics import mean_absolute_error
from sklearn.linear_model import Lasso
lasso = Lasso(alpha=0.0005)
pipe = Pipeline([('preprocess', preprocess), ('model', lasso)])
scores = cross_val_score(pipe, X, y, cv=5, scoring='neg_mean_absolute_error')
print('MAE:', -scores.mean())
---
## 5.7 MLflow 實驗追蹤
python
import mlflow
import mlflow.sklearn
mlflow.set_experiment('house_price_feature_engineering')
with mlflow.start_run():
# 參數記錄
mlflow.log_params({
'model': 'Lasso',
'alpha': 0.0005,
'preprocess_steps': 'StandardScaler + OneHotEncoder + log1p'
})
# 交叉驗證結果
mlflow.log_metric('mae_mean', -scores.mean())
mlflow.log_metric('mae_std', -scores.std())
# 重要性圖
pipe.fit(X, y)
mlflow.sklearn.log_model(pipe, artifact_path='model')
mlflow.log_artifact('feature_importance.png')
- **實驗元資料**:參數、指標、模型、重要性圖全被儲存於 MLflow Server,方便回溯。
- **可視化**:在 Jupyter Notebook 中使用 `mlflow.ui` 或 `mlflow.tracking` 直接觀察實驗結果。
---
## 5.8 DVC 版控與實驗可復現
bash
# 初始化 DVC
$ dvc init
# 追蹤原始數據
$ dvc add data/train.csv data/test.csv
# 建立 pipeline
$ dvc run -n feature_engineering \
-d src/feature_engineering.py -d data/train.csv -d data/test.csv \
-o data/processed/train_processed.csv \
python src/feature_engineering.py
# 推送到遠端儲存
$ dvc push
- **追蹤文件**:DVC 會產生 `.dvc` 檔案,描述輸入、輸出與執行命令。
- **版本回溯**:隨著 Git 版本切換,DVC 可重新執行相應的特徵工程流程,確保同一資料版本得到一致的特徵集。
---
## 5.9 可解釋性與洞察
- **SHAP**:用於解釋單一樣本預測;整體上計算 `mean(|SHAP|)`。
- **Permutation Importance**:驗證特徵對模型性能的影響。
python
import shap
explainer = shap.Explainer(pipe.predict, preprocess.transform(X))
shap_values = explainer(X)
shap.summary_plot(shap_values, X, show=False)
plt.savefig('shap_summary.png')
mlflow.log_artifact('shap_summary.png')
- **業務洞察**:將 SHAP 重要性回饋給業務部門,指出哪些建築特徵、區域特徵對價格影響最大,為房產投資決策提供科學依據。
---
## 5.10 小結與未來迭代
> **重點回顧**:
> - 先確定數據品質,然後從業務視角設計衍生特徵。
> - 利用統計檢驗(VIF、相關性)篩選,並保持可解釋性。
> - 每一次實驗都透過 MLflow、DVC 完全追蹤,確保可復現。
> - 最後以 SHAP 與 Permutation Importance 形成決策支援。
>
> **下一步**:
> 1. 探索非線性特徵組合(如多項式、交互項)。
> 2. 引入深度學習模型(如 TabNet)與 AutoML 進行模型集成。
> 3. 在實際商業環境中部署模型,結合實時數據流,形成可持續的洞察循環。
---
> **開放式結語**:資料科學的力量不只是數字的高低,更在於能夠將數據轉化為具體的商業價值。每一次特徵的迭代,都可能是一次新的洞察機會。把開放心態與嚴謹方法結合,您就能在數據的海洋中,捕捉到最具價值的寶藏。