線性迴歸:從最小平方法到可上線實務
標籤:
machinelearning,datascience,python,tutorial
線性迴歸是大多數人接觸的第一個演算法,也是許多人從未深入研究的模型。它也是在其他更複雜演算法失效後,仍能在實際環境中找到的模型,因為它快速、穩定且具可解釋性。
本文不是一份「呼叫 .fit() 再讀取分數」的教學。我們將涵蓋數學、統計假設、診斷、正則化、評估、上線考量,以及區分初學者與工程師的面試題目。
為什麼線性迴歸值得再看一眼
線性迴歸是理解幾乎所有其他監督式模型的基礎:
- 邏輯迴歸就是在線性迴歸上疊加一個 sigmoid 函數。
- Ridge 與 Lasso 就是在權重受限制下的線性迴歸。
- 神經網路就是一堆帶有非線性啟動函數的線性轉換堆疊。
- 樹模型通常會拿來跟同樣的基準比較:「我能打敗線性模型嗎?」
更重要的是,線性迴歸在許多商業問題中仍然是正確答案。當你需要向監管機構、客戶或財務團隊解釋預測結果時,一個乾淨且係數可解釋的線性模型,勝過黑盒子。
數學:最小平方法與正規方程式
給定特徵 X 與目標 y,線性模型假設:
y = X * beta + epsilon
Enter fullscreen mode Exit fullscreen mode
目標是最小化殘差平方和:
L(beta) = ||y - X*beta||^2
Enter fullscreen mode Exit fullscreen mode
對 beta 取導數並設為零,即可得到正規方程式:
beta = (X^T * X)^(-1) * X^T * y
Enter fullscreen mode Exit fullscreen mode
實務上,請使用偽逆矩陣 (pinv) 而非反矩陣,因為當特徵共線時 X^T X 可能為奇異矩陣或數值不穩定。
import numpy as np
def normal_equation(X, y):
Xb = np.c_[np.ones(X.shape[0]), X] # add intercept
beta = np.linalg.pinv(Xb.T @ Xb) @ Xb.T @ y
return beta
Enter fullscreen mode Exit fullscreen mode
最小平方法的三種等價觀點
1. 幾何觀點
預測值 X * beta 是 y 在 X 行空間中的投影。最小平方法找出該子空間中最接近的點。這也是為什麼殘差會與擬合值正交。
2. 最大似然觀點
假設:
epsilon ~ N(0, sigma^2)
Enter fullscreen mode Exit fullscreen mode
則最大化對數似然等同於最小化平方誤差和。此關聯解釋了為什麼殘差的常態性對信賴區間很重要,儘管在較弱的假設下 OLS 係數仍具一致性。
3. 最佳化觀點
對於大型資料集,計算 (X^T X)^(-1) 會變得很昂貴。梯度下降以迭代方式求解相同的目標:
def gradient_descent(X, y, lr=0.01, epochs=500):
Xb = np.c_[np.ones(X.shape[0]), X]
n, d = Xb.shape
beta = np.zeros(d)
for _ in range(epochs):
grad = (2 / n) * Xb.T @ (Xb @ beta - y)
beta -= lr * grad
return beta
Enter fullscreen mode Exit fullscreen mode
正規方程式:精確,適合中小型資料集。梯度下降:可擴展,但需要特徵縮放與學習率調整。
你必須檢查的假設
一個 R-squared 很高的模型並不自動值得信賴。讓係數可解釋的,正是這些假設:
| 假設 | 意義 | 檢查方式 |
|---|---|---|
| 線性 | 特徵與目標之間呈線性關係 | residual vs fitted 圖 |
| 獨立性 | 誤差不相關 | Durbin-Watson 統計量 |
| 同質變異數 | 誤差變異數恆定 | Breusch-Pagan 檢定、殘差圖 |
| 常態性 | 誤差呈常態分布 | Q-Q 圖、Jarque-Bera 檢定 |
| 無多重共線性 | 特徵之間不高度相關 | VIF、相關矩陣 |
完整診斷步驟
import statsmodels.api as sm
from statsmodels.stats.stattools import durbin_watson
from statsmodels.stats.diagnostic import het_breuschpagan
from statsmodels.stats.outliers_influence import variance_inflation_factor
from scipy import stats
import pandas as pd
X_const = sm.add_constant(X_train)
model = sm.OLS(y_train, X_const).fit()
resid = model.resid
print("Durbin-Watson:", durbin_watson(resid))
# Values near 2 mean no autocorrelation; near 0 or 4 is a warning.
lm, lm_pvalue, fvalue, f_pvalue = het_breuschpagan(resid, X_const)
print("Breusch-Pagan p-value:", f_pvalue)
# p > 0.05: no strong evidence of heteroscedasticity.
print("Jarque-Bera p-value:", stats.jarque_bera(resid).pvalue)
# p > 0.05: no strong evidence against normality.
vif = pd.DataFrame({
"feature": X_train.columns,
"VIF": [variance_inflation_factor(X_train.values, i)
for i in range(X_train.shape[1])],
})
print(vif)
# VIF > 10 is commonly treated as a multicollinearity warning.
Enter fullscreen mode Exit fullscreen mode
正則化:偏差-變異數權衡
普通最小平方法會最小化訓練誤差,當特徵眾多或共線時容易過擬合。正則化加入懲罰:
Ridge: L = MSE + alpha * sum(beta_i^2)
Lasso: L = MSE + alpha * sum(|beta_i|)
ElasticNet: L = MSE + alpha * (r * L1 + (1 - r) * L2)
Enter fullscreen mode Exit fullscreen mode
| 模型 | 懲罰 | 效果 | 最佳使用情境 |
|---|---|---|---|
| Ridge | L2 | 縮減權重,保留所有特徵 | 許多相關特徵 |
| Lasso | L1 | 將部分權重縮減至正好為零 | 需要特徵選擇 |
| ElasticNet | L1 + L2 | 在相關群組中稀疏且穩定 | 同時需要兩者 |
重要細節:在正則化之前務必先將特徵標準化,否則懲罰會不公平地縮減量值較大的特徵。
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression, Ridge, Lasso, ElasticNet
models = {
"OLS": LinearRegression(),
"Ridge(alpha=1)": Ridge(alpha=1.0),
"Lasso(alpha=0.01)": Lasso(alpha=0.01),
"ElasticNet(alpha=0.01)": ElasticNet(alpha=0.01, l1_ratio=0.5),
}
for name, model in models.items():
pipe = make_pipeline(StandardScaler(), model)
pipe.fit(X_train, y_train)
y_pred = pipe.predict(X_test)
print(f"{name:20s} RMSE={mean_squared_error(y_test, y_pred, squared=False):.4f} "
f"R2={r2_score(y_test, y_pred):.4f}")
Enter fullscreen mode Exit fullscreen mode
評估指標
不要只報告 R-squared。每個指標都告訴你不同的故事:
| 指標 | 公式意義 | 使用時機 |
|---|---|---|
| MAE | 平均絕對誤差 | 誤差不應平方、異常值影響較小 |
| RMSE | 均方根誤差 | 大誤差特別糟糕 |
| MAPE | 平均絕對百分比誤差 | 商業需要百分比解釋 |
| R² | 解釋變異比例 | 比較模型品質 |
| Adjusted R² | 依特徵數量懲罰後的 R² | 比較不同特徵集合的模型 |
永遠與平均值基準比較。如果你的模型只比「預測平均值」好一點,那特徵並沒有帶來太多幫助。
baseline_pred = np.full_like(y_test, y_train.mean())
print("Baseline RMSE:", mean_squared_error(y_test, baseline_pred, squared=False))
Enter fullscreen mode Exit fullscreen mode
完整端到端範例
import numpy as np
import pandas as pd
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
data = fetch_california_housing(as_frame=True)
X = data.frame.drop(columns=["MedHouseVal"])
y = data.frame["MedHouseVal"]
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# 1. Handcrafted normal equation
beta = normal_equation(X_train.values, y_train.values)
X_test_b = np.c_[np.ones(X_test.shape[0]), X_test.values]
y_pred_manual = X_test_b @ beta
# 2. sklearn baseline
from sklearn.linear_model import LinearRegression
lr = LinearRegression().fit(X_train, y_train)
y_pred_sklearn = lr.predict(X_test)
for name, y_pred in [("manual", y_pred_manual), ("sklearn", y_pred_sklearn)]:
print(f"{name}: RMSE={mean_squared_error(y_test, y_pred, squared=False):.4f} "
f"MAE={mean_absolute_error(y_test, y_pred):.4f} "
f"R2={r2_score(y_test, y_pred):.4f}")
Enter fullscreen mode Exit fullscreen mode
手動解與 sklearn 解應該產生幾乎相同的數字。如果不同,代表你的梯度下降尚未收斂,或特徵尚未縮放。
上線檢查清單
- 特徵縮放:梯度下降與正則化模型都需要。
- 交叉驗證:永遠不要在測試集上調整 alpha。
- 資料洩漏:在縮放、編碼或插補之前先分割。
- 監控:部署後追蹤特徵分布與預測漂移。
- 可解釋性:記錄係數、特徵重要性與 SHAP 值以供稽核。
- 從簡單開始:在嘗試 XGBoost 之前,先用線性迴歸。
常見錯誤
1. 相關不等於因果
高係數不代表改變特徵就會改變目標。遺漏變數與反向因果始終存在。
2. 外插
線性模型在訓練範圍之外很危險。在房屋面積最多 300 平方公尺上訓練的模型,無法告訴你 3000 平方公尺的房屋價格。
3. 高 R-squared 不代表預測好
R-squared 衡量樣本內擬合度。一個模型可能在訓練資料上有高 R-squared,但在未見資料上卻有很差的 RMSE。
4. 忽略殘差
如果殘差有模式,代表你的模型缺少結構。不要試圖盲目加入更多線性特徵來「修正」非線性模式。
5. 在正則化時使用原始特徵
沒有標準化,Ridge 與 Lasso 會對不同單位的特徵施加不平等的懲罰。
面試必備問題
- 正規方程式與梯度下降有什麼差別?
- 為什麼在常態誤差假設下 OLS 等同於最大似然?
- 如果
X^T X是奇異矩陣會發生什麼事?Ridge 怎麼幫助? - 如何偵測並修正多重共線性?
- 為什麼要用 adjusted R-squared 而非 R-squared?
- residual vs fitted 圖告訴你什麼?
- 什麼時候會偏好 Lasso 而非 Ridge?
- 為什麼在 L1 或 L2 正則化之前必須先標準化?
- 異質變異數的後果是什麼?
- 如何在迴歸管線中偵測資料洩漏?
結論
線性迴歸看似簡單,卻包含了機器學習的核心概念:目標函數、最佳化、統計假設、正則化、評估與部署。如果你深入理解這個模型,之後的每個演算法都會更容易學習。
從數學開始,驗證假設,並將上線考量放在心上。那個「太簡單」的模型,往往是在實際環境中存活最久的模型。
覺得有用嗎?歡迎追蹤我,獲取更多實務 AI 與資料工程文章。
沒 ;。l
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.