聊天視窗

數據科學的藝術與科學:從基礎到實踐 - 第 3 章

第三章:模型建構與評估

發布於 2026-02-25 14:41

# 第三章:模型建構與評估 > **章節目標**:本章將以剛剛整理好的銷售資料為基礎,帶領讀者完成兩類典型機器學習任務——迴歸預測與分類判斷,並探討評估指標、交叉驗證、超參數調整與模型可解釋性。 ## 3.1 先備工作:資料確認與切分 在進入建模之前,我們先把資料重新整理一次,確保所有特徵都已經轉為機器學習友好的格式。 python # 讀取剛整理好的 CSV import pandas as pd df = pd.read_csv('sales_cleaned.csv') print(df.head()) > 這裡的 `TotalPrice` 是我們的目標變數,作為迴歸任務。若將其二元化(>50元為高消費,≤50元為低消費),則可作為分類任務。 ### 資料切分 python from sklearn.model_selection import train_test_split X = df.drop(columns=['TotalPrice']) y = df['TotalPrice'] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) > **備註**:若要同時處理迴歸與分類,建議先定義兩個目標變數:`y_reg` 與 `y_cls`。分類目標可透過 `y_cls = (y > 50).astype(int)` 產生。 ## 3.2 迴歸模型:線性迴歸與隨機森林 ### 3.2.1 直觀解釋:線性迴歸 python from sklearn.linear_model import LinearRegression lin_reg = LinearRegression() lin_reg.fit(X_train, y_train) print('截距:', lin_reg.intercept_) print('係數:', dict(zip(X.columns, lin_reg.coef_))) > **解釋**:係數的正負直接說明該特徵對消費金額的影響方向;數值越大,影響越顯著。 ### 3.2.2 性能評估 python from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score pred_lin = lin_reg.predict(X_test) print('MAE:', mean_absolute_error(y_test, pred_lin)) print('RMSE:', mean_squared_error(y_test, pred_lin, squared=False)) print('R²:', r2_score(y_test, pred_lin)) > **常見陷阱**:若 `R²` 接近 0 或負值,表示模型無法捕捉資料變異,需考慮非線性模型或特徵工程。 ### 3.2.3 非線性補強:隨機森林迴歸 python from sklearn.ensemble import RandomForestRegressor rf_reg = RandomForestRegressor(n_estimators=500, random_state=42) rf_reg.fit(X_train, y_train) pred_rf = rf_reg.predict(X_test) print('MAE (RF):', mean_absolute_error(y_test, pred_rf)) print('RMSE (RF):', mean_squared_error(y_test, pred_rf, squared=False)) print('R² (RF):', r2_score(y_test, pred_rf)) > **說明**:隨機森林能自動處理非線性關係,且不易過擬合。若仍想提升,可調整 `max_depth`、`min_samples_leaf` 等參數。 ## 3.3 分類模型:邏輯回歸與XGBoost ### 3.3.1 目標設定 python y_cls = (y > 50).astype(int) X_train_cls, X_test_cls, y_train_cls, y_test_cls = train_test_split(X, y_cls, test_size=0.2, random_state=42) ### 3.3.2 基礎模型:邏輯回歸 python from sklearn.linear_model import LogisticRegression log_reg = LogisticRegression(max_iter=1000) log_reg.fit(X_train_cls, y_train_cls) ### 3.3.3 評估指標 python from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_auc_score pred_cls = log_reg.predict(X_test_cls) print('Accuracy:', accuracy_score(y_test_cls, pred_cls)) print('Precision:', precision_score(y_test_cls, pred_cls)) print('Recall:', recall_score(y_test_cls, pred_cls)) print('F1-Score:', f1_score(y_test_cls, pred_cls)) print('ROC AUC:', roc_auc_score(y_test_cls, log_reg.predict_proba(X_test_cls)[:,1])) > **小提醒**:若正負樣本比例失衡,建議使用 `class_weight='balanced'` 或調整 `threshold`。 ### 3.3.4 強化模型:XGBoost python import xgboost as xgb xgb_clf = xgb.XGBClassifier(n_estimators=400, learning_rate=0.05, max_depth=4, subsample=0.8, colsample_bytree=0.8, random_state=42) xgb_clf.fit(X_train_cls, y_train_cls) pred_xgb = xgb_clf.predict(X_test_cls) print('XGB Accuracy:', accuracy_score(y_test_cls, pred_xgb)) print('XGB ROC AUC:', roc_auc_score(y_test_cls, xgb_clf.predict_proba(X_test_cls)[:,1])) > **為什麼選擇 XGBoost**:它在處理高維度特徵、缺失值、非線性關係上表現優異,且易於調參。 ## 3.4 超參數調整:網格搜尋與隨機搜尋 ### 3.4.1 網格搜尋(GridSearchCV) python from sklearn.model_selection import GridSearchCV param_grid = { 'n_estimators': [200, 400, 600], 'max_depth': [3, 4, 5], 'learning_rate': [0.1, 0.05, 0.01] } gs = GridSearchCV(xgb.XGBClassifier(random_state=42), param_grid, cv=5, scoring='roc_auc', verbose=1) gs.fit(X_train_cls, y_train_cls) print('Best Params:', gs.best_params_) print('Best ROC AUC:', gs.best_score_) ### 3.4.2 隨機搜尋(RandomizedSearchCV) python from sklearn.model_selection import RandomizedSearchCV import scipy.stats as st param_dist = { 'n_estimators': st.randint(100, 1000), 'max_depth': st.randint(3, 10), 'learning_rate': st.uniform(0.01, 0.3), 'subsample': st.uniform(0.5, 1.0), 'colsample_bytree': st.uniform(0.5, 1.0) } rs = RandomizedSearchCV(xgb.XGBClassifier(random_state=42), param_distributions=param_dist, n_iter=50, cv=5, scoring='roc_auc', random_state=42) rs.fit(X_train_cls, y_train_cls) print('Best Params (Randomized):', rs.best_params_) print('Best ROC AUC (Randomized):', rs.best_score_) > **建議**:對於資源有限的情況,先用 RandomizedSearchCV 快速定位,再細化使用 GridSearchCV。 ## 3.5 交叉驗證與模型選擇 > **目的**:確保模型在不同資料子集上皆具備穩健性,避免過擬合。 python from sklearn.model_selection import cross_val_score cv_scores = cross_val_score(rf_reg, X, y, cv=10, scoring='neg_mean_squared_error') print('Cross-validated RMSE:', (-cv_scores.mean())**0.5) > **注意**:對於時間序列資料,請使用 `TimeSeriesSplit`;本例為非時間序列,採用 k‑fold。 ## 3.6 模型可解釋性 ### 3.6.1 SHAP 值 python import shap explainer = shap.TreeExplainer(rf_reg) shap_values = explainer.shap_values(X_test) shap.summary_plot(shap_values, X_test) > **解釋**:SHAP 值能量化每個特徵對預測的貢獻,讓非技術決策者也能理解模型。 ### 3.6.2 LIME(Local Interpretable Model‑agnostic Explanations) python from lime import lime_tabular explainer = lime_tabular.LimeTabularExplainer(X_train.values, feature_names=X.columns, class_names=['Low', 'High'], mode='classification') exp = explainer.explain_instance(X_test.values[0], rf_reg.predict_proba, num_features=5) exp.show_in_notebook(show_table=True, show_all=False) > **使用場景**:當模型複雜且無法一次性解釋所有輸入時,LIME 可針對單一樣本提供「本地」解釋。 ## 3.7 部署前的最後檢查 | 步驟 | 內容 | 目的 | |------|------|------| | 1 | **資料完整性檢查** | 確保無遺失值、極端值已處理 | | 2 | **版本控制** | 以 Git 或 DVC 紀錄資料、模型、程式碼版本 | | 3 | **模型序列化** | 使用 `joblib` / `pickle` / `onnx` 將模型儲存 | | 4 | **測試案例** | 寫單元測試確認輸入→輸出流程無誤 | | 5 | **監控指標** | 設定 `MLflow`、Prometheus 監控 `latency`、`accuracy` | python import joblib joblib.dump(rf_reg, 'models/rf_reg.pkl') > **小結**:上述流程將確保模型在實際環境中能穩定運行,並具備回溯與更新機制。 ## 3.8 小結 本章從資料準備開始,透過線性迴歸與隨機森林、邏輯回歸與 XGBoost,展現不同類型模型的建構與評估。進一步說明了交叉驗證、超參數調整、模型可解釋性與部署前檢查,為讀者提供了從「理論」到「實務」的完整流程。下一章將進一步探討模型監控、漂移偵測以及如何將模型落地於雲端服務。