機器學習之線性回歸(七)
文章目錄
- 機器學習之線性回歸(七)
- 一、線性回歸
- 線性回歸超全指南:從“一條直線”到“正則化調參”的完整旅程
- 0. 先對齊語言:標稱型 vs 連續型
- 1. 問題形式化
- 2. 損失函數全景
- 3. 求解方法 1:最小二乘(Normal Equation)
- 3.1 推導
- 3.2 代碼
- 4. 求解方法 2:梯度下降家族
- 4.1 統一更新公式
- 4.2 自己寫 SGD(單變量示例)
- 4.3 sklearn 一鍵調用
- 5. 特征工程三板斧
- 6. 正則化:專治過擬合
- 6.1 目標函數
- 6.2 調參模板(GridSearchCV)
- 7. 實戰:完整 Pipeline
- 8. 面試 8 連擊
- 9. 可視化:一條直線的前世今生
- 10. 總結腦圖(文字版)
一、線性回歸
線性回歸超全指南:從“一條直線”到“正則化調參”的完整旅程
面向:想徹底吃透線性回歸、并能在面試/競賽/生產中直接落地的同學
代碼:可直接復制運行,覆蓋最小二乘、批量/隨機/小批量梯度下降、Ridge/Lasso、特征工程、調參模板
0. 先對齊語言:標稱型 vs 連續型
類型 | 舉例 | 能否做加減 | 機器學習任務 |
---|---|---|---|
標稱型 Nominal | 顏色{紅, 綠, 藍}、性別{男, 女} | ? | 分類 |
連續型 Continuous | 溫度 23.7 ℃、房價 512.3 萬 | ? | 回歸 |
線性回歸只處理連續型目標變量 y。
1. 問題形式化
給定數據集 D={(x(i),y(i))}i=1m\mathcal{D} = \{(\mathbf{x}^{(i)}, y^{(i)})\}_{i=1}^{m}D={(x(i),y(i))}i=1m?,其中
- x(i)∈Rn\mathbf{x}^{(i)} \in \mathbb{R}^nx(i)∈Rn(一行 nnn 個特征)
- y(i)∈Ry^{(i)} \in \mathbb{R}y(i)∈R
我們希望學到一個函數
y^=f(x)=w?x+b\hat{y}=f(\mathbf{x})=\mathbf{w}^\top\mathbf{x}+b y^?=f(x)=w?x+b
使得預測誤差最小。為了寫矩陣方便,把 bbb 吸收進 w\mathbf{w}w:
y^=Xw\hat{\mathbf{y}} = X\mathbf{w} y^?=Xw
其中
- X∈Rm×(n+1)X\in\mathbb{R}^{m\times (n+1)}X∈Rm×(n+1):最后一列全 1,把偏置 bbb 當做 w0w_0w0?
- w∈Rn+1\mathbf{w}\in\mathbb{R}^{n+1}w∈Rn+1:待求參數
2. 損失函數全景
名稱 | 公式 | 特點 | 場景 |
---|---|---|---|
MSE (L2) | 1m∣y?Xw∣22\frac{1}{m}|\mathbf{y}-X\mathbf{w}|_2^2m1?∣y?Xw∣22? | 光滑、可導 | 默認 |
MAE (L1) | 1m∣y?Xw∣1\frac{1}{m}|\mathbf{y}-X\mathbf{w}|_1m1?∣y?Xw∣1? | 對異常值魯棒 | 數據臟 |
Huber | 混合 L1/L2 | 魯棒+光滑 | 競賽 |
Quantile | … | 預測分位數 | 金融風控 |
下文默認 MSE,因為閉式解 + 凸函數 + 可微。
3. 求解方法 1:最小二乘(Normal Equation)
3.1 推導
對 MSE 求導并令導數為 0:
?wLoss=?2X?(y?Xw)=0?X?Xw=X?y\nabla_{\mathbf{w}}\text{Loss}= -2X^\top(\mathbf{y}-X\mathbf{w})=0 \Rightarrow X^\top X\mathbf{w}=X^\top\mathbf{y} ?w?Loss=?2X?(y?Xw)=0?X?Xw=X?y
若 X?XX^\top XX?X 可逆,則
w=(X?X)?1X?y\boxed{\mathbf{w}=(X^\top X)^{-1}X^\top\mathbf{y}} w=(X?X)?1X?y?
時間復雜度:O(mn2+n3)O(mn^2+n^3)O(mn2+n3),特征 n>104n>10^4n>104 基本跑不動。
3.2 代碼
import numpy as np
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error# 1. 數據
X, y = fetch_california_housing(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)# 2. 手動最小二乘
X_b = np.c_[np.ones((X_train.shape[0], 1)), X_train] # 加一列 1
w_exact = np.linalg.inv(X_b.T @ X_b) @ X_b.T @ y_train# 3. 預測
X_test_b = np.c_[np.ones((X_test.shape[0], 1)), X_test]
y_pred = X_test_b @ w_exact
print("MSE (Normal):", mean_squared_error(y_test, y_pred))
4. 求解方法 2:梯度下降家族
4.1 統一更新公式
wt+1=wt?η?wLoss\mathbf{w}_{t+1} = \mathbf{w}_t - \eta \nabla_{\mathbf{w}}\text{Loss} wt+1?=wt??η?w?Loss
對 MSE:
?wLoss=2mX?(Xw?y)\nabla_{\mathbf{w}}\text{Loss}= \frac{2}{m}X^\top(X\mathbf{w}-\mathbf{y}) ?w?Loss=m2?X?(Xw?y)
算法 | 每次梯度計算量 | 更新頻率 | 優點 | 缺點 |
---|---|---|---|---|
BGD | 全量 mmm 條 | 1 epoch/次 | 穩定 | 慢 |
SGD | 1 條 | mmm epoch/次 | 快、可在線 | 噪聲大 |
MBGD | bbb 條(batch) | ?m/b?\lceil m/b\rceil?m/b? epoch/次 | 折中 | 需調 batch |
梯度下降圖解:
4.2 自己寫 SGD(單變量示例)
def sgd_linreg(X, y, lr=0.01, epochs=100, batch_size=32):m, n = X.shapeX = np.c_[np.ones(m), X] # 加偏置w = np.random.randn(n + 1)for epoch in range(epochs):idx = np.random.permutation(m)for i in range(0, m, batch_size):sl = idx[i:i+batch_size]grad = 2/len(sl) * X[sl].T @ (X[sl] @ w - y[sl])w -= lr * gradreturn w
4.3 sklearn 一鍵調用
from sklearn.linear_model import SGDRegressor
from sklearn.preprocessing import StandardScalerscaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train)
X_test_s = scaler.transform(X_test)sgd = SGDRegressor(loss='squared_error',penalty='l2', # Ridgealpha=1e-4, # 正則強度 λlearning_rate='adaptive',eta0=0.01,max_iter=1000,random_state=42)sgd.fit(X_train_s, y_train)
print("MSE (SGD):", mean_squared_error(y_test, sgd.predict(X_test_s)))
5. 特征工程三板斧
- 標準化:梯度下降必須!
StandardScaler
或RobustScaler
(對異常值穩)。 - 多項式特征:線性不可分時升維
from sklearn.preprocessing import PolynomialFeatures poly = PolynomialFeatures(degree=2, include_bias=False) X_poly = poly.fit_transform(X)
- 離散特征編碼:One-Hot 后當作數值即可。
6. 正則化:專治過擬合
6.1 目標函數
- Ridge (L2):
Loss=12m∥y?Xw∥22+λ∥w∥22\text{Loss}= \frac{1}{2m}\|\mathbf{y}-X\mathbf{w}\|_2^2 + \lambda\|\mathbf{w}\|_2^2 Loss=2m1?∥y?Xw∥22?+λ∥w∥22? - Lasso (L1):
Loss=12m∥y?Xw∥22+λ∥w∥1\text{Loss}= \frac{1}{2m}\|\mathbf{y}-X\mathbf{w}\|_2^2 + \lambda\|\mathbf{w}\|_1 Loss=2m1?∥y?Xw∥22?+λ∥w∥1? - Elastic Net:L1 + L2 的加權組合。
6.2 調參模板(GridSearchCV)
from sklearn.model_selection import GridSearchCV
from sklearn.linear_model import RidgeCV, LassoCValphas = np.logspace(-3, 3, 20)
ridge = RidgeCV(alphas=alphas, cv=5)
ridge.fit(X_train_s, y_train)
print("Best α Ridge:", ridge.alpha_)
7. 實戰:完整 Pipeline
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler, PolynomialFeatures
from sklearn.linear_model import Ridgepipe = Pipeline([('scaler', StandardScaler()),('poly', PolynomialFeatures(degree=2, include_bias=False)),('reg', Ridge(alpha=1.0))
])pipe.fit(X_train, y_train)
print("Test MSE:", mean_squared_error(y_test, pipe.predict(X_test)))
8. 面試 8 連擊
- 最小二乘一定可逆嗎?
不一定,需 X?XX^\top XX?X 滿秩;不可逆時用偽逆或加 λI\lambda IλI(Ridge)。 - MSE vs MAE 對異常值?
MSE 平方放大異常值;MAE 線性增長。 - 梯度下降為什么會震蕩?
學習率過大 or 特征未標準化。 - L1 為什么能做特征選擇?
解空間為菱形,最優解易落在頂點 → 某些權重=0。 - Ridge 與 Lasso 何時選?
高維+稀疏 → Lasso;特征相關性強 → Ridge。 - 多項式升維后還是線性回歸嗎?
對 參數 仍線性,對 特征 非線性。 - SGD 如何選 batch_size?
小數據 32~256;GPU 訓練可 1024+。 - 如何監控收斂?
畫loss vs epoch
曲線;早停(Early Stopping)。
9. 可視化:一條直線的前世今生
import matplotlib.pyplot as plt
plt.scatter(X_train[:,0], y_train, s=5)
plt.plot(X_test[:,0], ridge.predict(X_test), 'r')
plt.title("Ridge Regression on California Housing")
plt.show()
10. 總結腦圖(文字版)
數據 → 清洗/標準化 → 特征工程(多項式/離散化) ↓選模型├─ 最小二乘(閉式解) —— 小數據、可解釋├─ 梯度下降家族 —— 大數據、在線學習│ ├─ BGD(全量)│ ├─ MBGD(batch)│ └─ SGD(單條)└─ 正則化├─ Ridge(L2)├─ Lasso(L1)└─ Elastic Net↓評估(MSE/R2/MAE) → 調參(α, degree, batch, lr) → 上線