聊天視窗

數據科學:從原始資料到策略洞察 - 第 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. 在實際商業環境中部署模型,結合實時數據流,形成可持續的洞察循環。 --- > **開放式結語**:資料科學的力量不只是數字的高低,更在於能夠將數據轉化為具體的商業價值。每一次特徵的迭代,都可能是一次新的洞察機會。把開放心態與嚴謹方法結合,您就能在數據的海洋中,捕捉到最具價值的寶藏。