理论与实践结合,从数学本质到工程落地
目录
- 核心概念:机器学习的本质
- [回归分析 Regression](#回归分析 Regression)
- [分类任务 Classification](#分类任务 Classification)
- [回归 vs 分类:核心对比](#回归 vs 分类:核心对比)
- 模型评估与选择
- 实战案例
- 常见误区与最佳实践
1. 核心概念:机器学习的本质
1.1 什么是监督学习
机器学习的目标是从数据中学习一个映射函数:
y = f ( x ; θ ) y = f(\mathbf{x}; \boldsymbol{\theta}) y=f(x;θ)
其中:
- x ∈ R d \mathbf{x} \in \mathbb{R}^d x∈Rd --- 输入特征向量( d d d 维)
- y y y --- 目标输出
- θ \boldsymbol{\theta} θ --- 模型需要学习的参数
- f f f --- 模型假设的函数形式
核心流程:
数据收集 → 特征工程 → 模型选择 → 训练优化 → 评估部署
↑_____________________________________________↓
反馈迭代
1.2 回归与分类的本质区别
| 维度 | 回归 Regression | 分类 Classification |
|---|---|---|
| 输出类型 | 连续值 R \mathbb{R} R | 离散类别 { 0 , 1 , . . . , K } \{0, 1, ..., K\} {0,1,...,K} |
| 数学本质 | 拟合连续函数 | 寻找决策边界 |
| 核心问题 | "这个值是多少?" | "这个样本属于哪类?" |
| 损失函数 | MSE, MAE, Huber | Cross-Entropy, Hinge, Focal |
| 评估指标 | RMSE, MAE, R 2 R^2 R2 | Accuracy, F1, AUC-ROC |
| 典型场景 | 房价预测、股票预测 | 垃圾邮件检测、图像识别 |
2. 回归分析 Regression
2.1 线性回归 --- 一切的起点
数学模型
线性回归假设目标值是特征的线性组合:
y ^ = w T x + b = w 1 x 1 + w 2 x 2 + ⋯ + w d x d + b \hat{y} = \mathbf{w}^T\mathbf{x} + b = w_1 x_1 + w_2 x_2 + \cdots + w_d x_d + b y^=wTx+b=w1x1+w2x2+⋯+wdxd+b
矩阵形式 (含 m m m 个样本):
y ^ = X w + b 1 \hat{\mathbf{y}} = \mathbf{X}\mathbf{w} + b\mathbf{1} y^=Xw+b1
损失函数:均方误差 MSE
J ( w , b ) = 1 2 m ∑ i = 1 m ( y ^ ( i ) − y ( i ) ) 2 J(\mathbf{w}, b) = \frac{1}{2m} \sum_{i=1}^{m} (\hat{y}^{(i)} - y^{(i)})^2 J(w,b)=2m1i=1∑m(y^(i)−y(i))2
系数 1 2 \frac{1}{2} 21 是为了求导时消去平方的系数,使梯度更简洁:
∂ J ∂ w = 1 m X T ( X w − y ) \frac{\partial J}{\partial \mathbf{w}} = \frac{1}{m}\mathbf{X}^T(\mathbf{X}\mathbf{w} - \mathbf{y}) ∂w∂J=m1XT(Xw−y)
解析解 vs 迭代解
正规方程(解析解):
w ∗ = ( X T X ) − 1 X T y \mathbf{w}^* = (\mathbf{X}^T\mathbf{X})^{-1}\mathbf{X}^T\mathbf{y} w∗=(XTX)−1XTy
- ✅ 一次计算,精确解
- ❌ 时间复杂度 O ( d 3 ) O(d^3) O(d3),特征多时不可行
- ❌ X T X \mathbf{X}^T\mathbf{X} XTX 可能不可逆(需加正则化 → 岭回归)
梯度下降(迭代解):
w : = w − α ∂ J ∂ w \mathbf{w} := \mathbf{w} - \alpha \frac{\partial J}{\partial \mathbf{w}} w:=w−α∂w∂J
- ✅ 适用于大规模数据
- ❌ 需要选择学习率 α \alpha α
- ❌ 可能收敛到局部最优(非凸函数时)
Python 实战:线性回归
python
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
# 生成模拟数据:房价 = 面积×3.5 + 卧室数×2.8 + 噪音
np.random.seed(42)
n_samples = 500
area = np.random.uniform(50, 200, n_samples) # 面积 (m²)
bedrooms = np.random.randint(1, 5, n_samples) # 卧室数
noise = np.random.normal(0, 15, n_samples) # 噪音
price = area * 3.5 + bedrooms * 28.0 + noise + 50 # 真实关系
X = np.column_stack([area, bedrooms])
y = price
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
model = LinearRegression()
model.fit(X_train, y_train)
print(f"截距 b: {model.intercept_:.2f}")
print(f"面积系数: {model.coef_[0]:.2f} (真实值: 3.5)")
print(f"卧室系数: {model.coef_[1]:.2f} (真实值: 28.0)")
print(f"R² 得分: {r2_score(y_test, model.predict(X_test)):.4f}")
# 输出示例:
# 截距 b: 48.32
# 面积系数: 3.51 (真实值: 3.5)
# 卧室系数: 27.86 (真实值: 28.0)
# R² 得分: 0.9782
2.2 多项式回归 --- 曲线也能线性
当数据呈曲线关系时,可通过特征升维将非线性问题转化为线性:
y ^ = w 0 + w 1 x + w 2 x 2 + ⋯ + w p x p \hat{y} = w_0 + w_1 x + w_2 x^2 + \cdots + w_p x^p y^=w0+w1x+w2x2+⋯+wpxp
本质是将 x x x 映射为 x , x 2 , x 3 , . . . , x p x, x\^2, x\^3, ..., x\^p x,x2,x3,...,xp,再用线性回归。
关键权衡 --- 偏差-方差困境:
| p p p 太小 | p p p 太大 |
|---|---|
| 欠拟合 (高偏差) | 过拟合 (高方差) |
| 模型太简单,无法捕捉规律 | 模型太复杂,记住噪音 |
python
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline
# 多项式回归 Pipeline
poly_model = Pipeline([
('poly', PolynomialFeatures(degree=3)), # 生成 x, x², x³
('linear', LinearRegression())
])
poly_model.fit(X_train, y_train)
2.3 正则化回归 --- 控制过拟合
岭回归 Ridge (L2 正则化)
J ( w ) = 1 2 m ∥ X w − y ∥ 2 2 + λ ∥ w ∥ 2 2 J(\mathbf{w}) = \frac{1}{2m}\|\mathbf{X}\mathbf{w} - \mathbf{y}\|_2^2 + \lambda \|\mathbf{w}\|_2^2 J(w)=2m1∥Xw−y∥22+λ∥w∥22
- 惩罚所有权重的平方和,使权重趋于小值但不为零
- λ \lambda λ 越大 → 模型越简单 → 偏差越大
- 有解析解: w ∗ = ( X T X + λ I ) − 1 X T y \mathbf{w}^* = (\mathbf{X}^T\mathbf{X} + \lambda \mathbf{I})^{-1}\mathbf{X}^T\mathbf{y} w∗=(XTX+λI)−1XTy
Lasso 回归 (L1 正则化)
J ( w ) = 1 2 m ∥ X w − y ∥ 2 2 + λ ∥ w ∥ 1 J(\mathbf{w}) = \frac{1}{2m}\|\mathbf{X}\mathbf{w} - \mathbf{y}\|_2^2 + \lambda \|\mathbf{w}\|_1 J(w)=2m1∥Xw−y∥22+λ∥w∥1
- 惩罚权重的绝对值和 ,可产生稀疏解(部分权重精确为零)
- 🎯 天然的特征选择器:不重要特征的权重直接被压缩到 0
弹性网络 Elastic Net
J ( w ) = 1 2 m ∥ X w − y ∥ 2 2 + λ ( ρ ∥ w ∥ 1 + 1 − ρ 2 ∥ w ∥ 2 2 ) J(\mathbf{w}) = \frac{1}{2m}\|\mathbf{X}\mathbf{w} - \mathbf{y}\|_2^2 + \lambda (\rho\|\mathbf{w}\|_1 + \frac{1-\rho}{2}\|\mathbf{w}\|_2^2) J(w)=2m1∥Xw−y∥22+λ(ρ∥w∥1+21−ρ∥w∥22)
- 结合 L1 和 L2 的优点
- ρ \rho ρ 控制 L1/L2 的混合比例
python
from sklearn.linear_model import Ridge, Lasso, ElasticNet
# 对比三种正则化
for name, model in [
("Ridge α=1.0", Ridge(alpha=1.0)),
("Lasso α=0.1", Lasso(alpha=0.1)),
("ElasticNet α=0.1", ElasticNet(alpha=0.1, l1_ratio=0.5)),
]:
model.fit(X_train, y_train)
print(f"{name}: R²={r2_score(y_test, model.predict(X_test)):.4f}")
2.4 回归应用场景一览
| 应用领域 | 具体场景 | 常用模型 |
|---|---|---|
| 🏠 房地产 | 房价评估、租金预测 | XGBoost, LightGBM |
| 📈 金融 | 股票收益率预测、风险评估 | 时间序列 + LSTM |
| 🏭 制造业 | 设备剩余寿命预测、能耗预估 | 随机森林, 神经网络 |
| 🛒 电商 | 销量预测、用户LTV预测 | Gradient Boosting |
| 🚗 交通 | 到达时间预估、需求预测 | 深度学习 + 时空特征 |
| 🌦️ 气象 | 温度/降雨量预测 | 时间序列模型 |
| 💊 医疗 | 药物剂量-反应关系 | 非线性回归 |
3. 分类任务 Classification
3.1 逻辑回归 --- 虽是"回归"实则分类
逻辑回归将线性输出通过 Sigmoid 函数 映射到 0 , 1 0, 1 0,1,解释为概率:
数学模型
线性部分(logit / 对数几率):
z = w T x + b z = \mathbf{w}^T\mathbf{x} + b z=wTx+b
Sigmoid 激活:
p ^ = σ ( z ) = 1 1 + e − z \hat{p} = \sigma(z) = \frac{1}{1 + e^{-z}} p^=σ(z)=1+e−z1
决策规则:
y ^ = { 1 , p ^ ≥ 0.5 0 , p ^ < 0.5 \hat{y} = \begin{cases} 1, & \hat{p} \geq 0.5 \\ 0, & \hat{p} < 0.5 \end{cases} y^={1,0,p^≥0.5p^<0.5
为什么叫"对数几率回归"?
几率(odds)与对数几率(log-odds):
odds = p 1 − p ln ( p 1 − p ) = w T x + b \text{odds} = \frac{p}{1-p} \qquad \ln\left(\frac{p}{1-p}\right) = \mathbf{w}^T\mathbf{x} + b odds=1−ppln(1−pp)=wTx+b
逻辑回归实际上是用线性模型去拟合对数几率。
损失函数:交叉熵 Cross-Entropy
J ( w ) = − 1 m ∑ i = 1 m y ( i ) log ( p \^ ( i ) ) + ( 1 − y ( i ) ) log ( 1 − p \^ ( i ) ) J(\mathbf{w}) = -\frac{1}{m}\sum_{i=1}^{m} \left y\^{(i)}\\log(\\hat{p}\^{(i)}) + (1-y\^{(i)})\\log(1-\\hat{p}\^{(i)}) \\right J(w)=−m1i=1∑my(i)log(p\^(i))+(1−y(i))log(1−p\^(i))
为什么不用 MSE?
- Sigmoid + MSE 会导致梯度消失(预测极端错误时梯度接近 0,学习停滞)
- 交叉熵配合 Sigmoid,梯度为 p ^ − y \hat{p} - y p^−y,预测越错梯度越大 → 学得越快
python
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_classification
from sklearn.metrics import classification_report, confusion_matrix
# 生成二分类数据
X, y = make_classification(
n_samples=1000, n_features=10, n_informative=5,
n_redundant=2, random_state=42
)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
clf = LogisticRegression(C=1.0, max_iter=1000) # C = 1/λ
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
y_prob = clf.predict_proba(X_test)[:, 1] # 正类概率
print(classification_report(y_test, y_pred))
3.2 决策树 --- 可解释的分类器
核心思想
递归地将数据空间划分为纯净的区域:
[根节点: 年龄 ≤ 35?]
/ \
[是] [否]
/ \
[收入 ≤ 2万?] [婚姻=已婚?]
/ \ / \
[不买] [购买!] [购买!] [不买]
分裂准则
信息增益(ID3):
Gain ( D , A ) = H ( D ) − ∑ v ∣ D v ∣ ∣ D ∣ H ( D v ) \text{Gain}(D, A) = H(D) - \sum_{v} \frac{|D_v|}{|D|} H(D_v) Gain(D,A)=H(D)−v∑∣D∣∣Dv∣H(Dv)
其中熵 H ( D ) = − ∑ k p k log 2 p k H(D) = -\sum_{k} p_k \log_2 p_k H(D)=−∑kpklog2pk
基尼系数(CART):
Gini ( D ) = 1 − ∑ k = 1 K p k 2 \text{Gini}(D) = 1 - \sum_{k=1}^{K} p_k^2 Gini(D)=1−k=1∑Kpk2
- 基尼系数越低 → 节点越纯净
- CART 树默认使用基尼系数,计算比熵更高效
3.3 SVM 支持向量机 --- 寻找最大间隔
核心直觉
在数据之间画一条线,使得离这条线最近的样本点距离最大。
硬间隔 SVM(线性可分时):
min w , b 1 2 ∥ w ∥ 2 s.t. y ( i ) ( w T x ( i ) + b ) ≥ 1 , ∀ i \begin{aligned} \min_{\mathbf{w}, b} \quad & \frac{1}{2}\|\mathbf{w}\|^2 \\ \text{s.t.} \quad & y^{(i)}(\mathbf{w}^T\mathbf{x}^{(i)} + b) \geq 1, \quad \forall i \end{aligned} w,bmins.t.21∥w∥2y(i)(wTx(i)+b)≥1,∀i
软间隔 SVM(允许一定误分类):
min w , b , ξ 1 2 ∥ w ∥ 2 + C ∑ i = 1 m ξ i \min_{\mathbf{w}, b, \xi} \quad \frac{1}{2}\|\mathbf{w}\|^2 + C\sum_{i=1}^{m} \xi_i w,b,ξmin21∥w∥2+Ci=1∑mξi
- C C C 控制对误分类的惩罚力度
- C C C 大 → 硬间隔倾向 → 可能过拟合
- C C C 小 → 软间隔倾向 → 泛化能力强
核技巧 Kernel Trick
当数据不是线性可分时,通过核函数隐式映射到高维空间:
| 核函数 | 公式 | 适用场景 |
|---|---|---|
| 线性核 | K ( x , z ) = x T z K(x,z) = x^Tz K(x,z)=xTz | 高维稀疏特征(文本) |
| 多项式核 | K ( x , z ) = ( x T z + c ) d K(x,z) = (x^Tz + c)^d K(x,z)=(xTz+c)d | 已知多项式关系 |
| RBF 核 | K ( x , z ) = exp ( − γ ∣ x − z ∣ 2 ) K(x,z) = \exp(-\gamma|x-z|^2) K(x,z)=exp(−γ∣x−z∣2) | 最常用,通用型 |
| Sigmoid 核 | K ( x , z ) = tanh ( γ x T z + c ) K(x,z) = \tanh(\gamma x^Tz + c) K(x,z)=tanh(γxTz+c) | 类神经网络效果 |
python
from sklearn.svm import SVC
# RBF 核 SVM
svm = SVC(kernel='rbf', C=1.0, gamma='scale', probability=True)
svm.fit(X_train, y_train)
3.4 集成学习 --- 众人拾柴火焰高
Bagging → 随机森林
原始数据 → Bootstrap采样
├── 子集1 → 决策树1
├── 子集2 → 决策树2
├── ...
└── 子集N → 决策树N
↓
投票/平均 → 最终结果
随机森林 = Bagging + 随机特征选择(每次分裂只考虑部分特征)
Boosting → XGBoost / LightGBM
顺序训练弱学习器,每个新学习器专注于前一个犯的错误:
样本权重1 → 学习器1 → 计算误差 → 更新权重(错误样本加权重)
→ 学习器2 → 计算误差 → 更新权重
→ 学习器3 → ...
→ 加权组合 → 强学习器
| 算法 | 特点 | 何时使用 |
|---|---|---|
| AdaBoost | 按样本错误加权 | 简单二分类 |
| GBDT | 梯度提升,拟合残差 | 通用回归/分类 |
| XGBoost | 二阶导数 + 正则化 | Kaggle 竞赛首选 |
| LightGBM | 直方图加速 + Leaf-wise | 大规模数据 |
| CatBoost | 原生类别特征支持 | 大量类别型特征 |
python
from xgboost import XGBClassifier
from lightgbm import LGBMClassifier
xgb = XGBClassifier(n_estimators=100, learning_rate=0.1, max_depth=5)
xgb.fit(X_train, y_train)
lgb = LGBMClassifier(n_estimators=100, learning_rate=0.1, num_leaves=31)
lgb.fit(X_train, y_train)
print(f"XGBoost Accuracy: {xgb.score(X_test, y_test):.4f}")
print(f"LightGBM Accuracy: {lgb.score(X_test, y_test):.4f}")
3.5 多分类问题
一对多 OvR (One-vs-Rest)
对 K K K 个类别,训练 K K K 个二分类器:
- 分类器 k k k:类别 k k k vs 其他所有类别
- 预测时选得分最高的类别
一对一 OvO (One-vs-One)
训练 ( K 2 ) \binom{K}{2} (2K) 个二分类器,每对类别一个:
- 分类器 ( i , j ) (i,j) (i,j):类别 i i i vs 类别 j j j
- 预测时投票决定
Softmax 回归(多分类逻辑回归)
直接输出每个类别的概率:
P ( y = k ∣ x ) = e w k T x + b k ∑ j = 1 K e w j T x + b j P(y=k|\mathbf{x}) = \frac{e^{\mathbf{w}k^T\mathbf{x} + b_k}}{\sum{j=1}^{K} e^{\mathbf{w}_j^T\mathbf{x} + b_j}} P(y=k∣x)=∑j=1KewjTx+bjewkTx+bk
损失函数 --- 多分类交叉熵:
J = − 1 m ∑ i = 1 m ∑ k = 1 K y k ( i ) log p ^ k ( i ) J = -\frac{1}{m}\sum_{i=1}^{m}\sum_{k=1}^{K} y_k^{(i)} \log \hat{p}_k^{(i)} J=−m1i=1∑mk=1∑Kyk(i)logp^k(i)
3.6 分类应用场景一览
| 应用领域 | 具体场景 | 类别数 | 常用模型 |
|---|---|---|---|
| 📧 反垃圾邮件 | 邮件二分类 | 2 | 朴素贝叶斯, 逻辑回归 |
| 🏥 医疗诊断 | 疾病预测 / 影像判读 | 2~N | CNN, 随机森林 |
| 💳 金融风控 | 欺诈检测、信用评分 | 2 | XGBoost, 孤立森林 |
| 📝 NLP | 情感分析、意图识别 | 2~N | BERT, LSTM |
| 🖼️ 计算机视觉 | 图像分类、目标检测 | N (可达数万) | ResNet, ViT |
| 🎯 推荐系统 | CTR 预估(点/不点) | 2 | 深度网络 + FM |
| 🏷️ 文本分类 | 新闻分类、标签推荐 | N | FastText, Transformer |
4. 回归 vs 分类:核心对比
4.1 数学本质对比
回归: 分类:
y y
↑ ↑
| ✦ ✦ | ■ ■ ■
| ✦ ✦ | ■ ■ ■ ■
| ✦ ↑ ✦ | ← 决策边界 →
|✦ | ✦ | ○ ○ ○ ○ ○
|____|______→ x |____|_________→ x
连续曲线拟合 离散区域划分
4.2 损失函数选择指南
| 场景 | 推荐损失函数 | 原因 |
|---|---|---|
| 回归 --- 无异常值 | MSE | 梯度平滑,收敛稳定 |
| 回归 --- 有异常值 | MAE / Huber | 对异常值不敏感 |
| 回归 --- 需分位数 | Quantile Loss | 可预测区间 |
| 二分类 | Binary Cross-Entropy | 与概率解释一致 |
| 多分类 | Categorical Cross-Entropy | Softmax 的标准搭配 |
| 类别不均衡 | Focal Loss | 聚焦难分类样本 |
| 排序任务 | Pairwise / Listwise | 优化相对顺序 |
4.3 何时回归可以转化为分类
有时将回归问题离散化为分类更有效:
| 原回归问题 | 转化后的分类问题 | 动机 |
|---|---|---|
| 预测评分 1-5 | 5 分类 | 评分本质是离散的 |
| 股价涨跌幅 | 涨/平/跌 3 分类 | 交易只关心方向 |
| 用户年龄 | 年龄段分类 | 营销按年龄段 |
5. 模型评估与选择
5.1 回归评估指标
MSE / RMSE --- 最常用
MSE = 1 m ∑ i = 1 m ( y i − y ^ i ) 2 RMSE = MSE \text{MSE} = \frac{1}{m}\sum_{i=1}^{m} (y_i - \hat{y}_i)^2 \qquad \text{RMSE} = \sqrt{\text{MSE}} MSE=m1i=1∑m(yi−y^i)2RMSE=MSE
- RMSE 与目标变量同单位,更容易解释
- 对大误差惩罚极重(平方效应)
MAE --- 对异常值更鲁棒
MAE = 1 m ∑ i = 1 m ∣ y i − y ^ i ∣ \text{MAE} = \frac{1}{m}\sum_{i=1}^{m} |y_i - \hat{y}_i| MAE=m1i=1∑m∣yi−y^i∣
- 所有误差等权对待
- 预测偏离真实值 k k k 单位 → 惩罚就是 k k k
R 2 R^2 R2 --- 拟合优度
R 2 = 1 − ∑ i ( y i − y ^ i ) 2 ∑ i ( y i − y ˉ ) 2 R^2 = 1 - \frac{\sum_i (y_i - \hat{y}_i)^2}{\sum_i (y_i - \bar{y})^2} R2=1−∑i(yi−yˉ)2∑i(yi−y^i)2
- R 2 = 1 R^2 = 1 R2=1:完美拟合
- R 2 = 0 R^2 = 0 R2=0:和用均值预测一样差
- R 2 < 0 R^2 < 0 R2<0:比直接用均值预测还差!
python
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
y_pred = model.predict(X_test)
print(f"RMSE: {np.sqrt(mean_squared_error(y_test, y_pred)):.2f}")
print(f"MAE: {mean_absolute_error(y_test, y_pred):.2f}")
print(f"R²: {r2_score(y_test, y_pred):.4f}")
5.2 分类评估指标
混淆矩阵 --- 一切评估的起点
| 预测正类 | 预测负类 | |
|---|---|---|
| 实际正类 | TP (True Positive) | FN (False Negative) ❌ |
| 实际负类 | FP (False Positive) ❌ | TN (True Negative) |
核心指标
准确率 Accuracy:
Accuracy = T P + T N T P + T N + F P + F N \text{Accuracy} = \frac{TP + TN}{TP + TN + FP + FN} Accuracy=TP+TN+FP+FNTP+TN
- ⚠️ 类别不均衡时极具误导性(如 99% 负类,全猜负也有 99% 准确率)
精确率 Precision:
Precision = T P T P + F P \text{Precision} = \frac{TP}{TP + FP} Precision=TP+FPTP
- "模型说它是正类的样本里,有多少真的是正类?"
- 关注 FP → 误报代价高时(如垃圾邮件误判)
召回率 Recall:
Recall = T P T P + F N \text{Recall} = \frac{TP}{TP + FN} Recall=TP+FNTP
- "真正的正类样本中,有多少被模型找到了?"
- 关注 FN → 漏报代价高时(如疾病筛查)
F1 Score --- 精确率与召回率的调和平均:
F 1 = 2 ⋅ Precision ⋅ Recall Precision + Recall F_1 = 2 \cdot \frac{\text{Precision} \cdot \text{Recall}}{\text{Precision} + \text{Recall}} F1=2⋅Precision+RecallPrecision⋅Recall
- 使用调和平均 而非算术平均:两个指标中任何一个低, F 1 F_1 F1 都会低
ROC 曲线 与 AUC
TPR (Recall) = T P T P + F N FPR = F P F P + T N \text{TPR (Recall)} = \frac{TP}{TP + FN} \qquad \text{FPR} = \frac{FP}{FP + TN} TPR (Recall)=TP+FNTPFPR=FP+TNFP
- ROC 曲线:以 FPR 为横轴、TPR 为纵轴,变化分类阈值绘制
- AUC :ROC 曲线下的面积
- AUC = 1.0 → 完美分类器
- AUC = 0.5 → 随机猜测
- AUC < 0.5 → 比随机还差(反向使用即可)
python
from sklearn.metrics import (
confusion_matrix, classification_report,
roc_auc_score, f1_score, precision_score, recall_score
)
y_prob = model.predict_proba(X_test)[:, 1]
print(f"AUC-ROC: {roc_auc_score(y_test, y_prob):.4f}")
print(f"F1: {f1_score(y_test, y_pred):.4f}")
print(f"Precision:{precision_score(y_test, y_pred):.4f}")
print(f"Recall: {recall_score(y_test, y_pred):.4f}")
print("\n混淆矩阵:")
print(confusion_matrix(y_test, y_pred))
5.3 模型选择策略
┌─────────────┐
│ 数据规模? │
└──────┬──────┘
┌───────┴───────┐
小数据(<10K) 大数据(>100K)
│ │
┌───────┴───────┐ ┌───┴────┐
线性可分? 非线性? 文本? 表格?
│ │ │ │
逻辑回归 SVM/RF 朴素贝叶斯 XGBoost
线性SVM XGBoost /FastText /LightGBM
/深度网络
6. 实战案例
6.1 回归案例:波士顿房价预测完整流程
python
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split, cross_val_score, GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
from sklearn.linear_model import Ridge
from sklearn.metrics import mean_squared_error, r2_score
import matplotlib.pyplot as plt
# ─── 1. 数据加载与探索 ───
from sklearn.datasets import fetch_california_housing
data = fetch_california_housing()
df = pd.DataFrame(data.data, columns=data.feature_names)
df['Price'] = data.target
print(f"数据形状: {df.shape}")
print(f"缺失值:\n{df.isnull().sum()}")
print(f"\n统计描述:\n{df.describe().round(2)}")
# ─── 2. 特征工程 ───
# 创建交互特征
df['RoomsPerHouse'] = df['AveRooms'] / df['AveOccup']
df['BedroomRatio'] = df['AveBedrms'] / df['AveRooms']
# 分离特征和标签
X = df.drop('Price', axis=1)
y = df['Price']
# ─── 3. 数据集划分 ───
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# ─── 4. 特征标准化 ───
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
# ─── 5. 模型对比 ───
models = {
'Ridge': Ridge(alpha=1.0),
'RandomForest': RandomForestRegressor(n_estimators=100, random_state=42),
'GradientBoosting': GradientBoostingRegressor(n_estimators=100, random_state=42),
}
for name, model in models.items():
model.fit(X_train_scaled, y_train)
y_pred = model.predict(X_test_scaled)
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
r2 = r2_score(y_test, y_pred)
print(f"{name:20s} | RMSE: {rmse:.4f} | R²: {r2:.4f}")
# ─── 6. 超参数调优 ───
param_grid = {
'n_estimators': [100, 200, 300],
'max_depth': [5, 10, 15, None],
'min_samples_split': [2, 5, 10],
}
grid = GridSearchCV(
RandomForestRegressor(random_state=42),
param_grid, cv=5, scoring='neg_mean_squared_error', n_jobs=-1
)
grid.fit(X_train_scaled, y_train)
print(f"\n最佳参数: {grid.best_params_}")
print(f"最佳 RMSE: {np.sqrt(-grid.best_score_):.4f}")
# ─── 7. 特征重要性 ───
best_model = grid.best_estimator_
importances = best_model.feature_importances_
indices = np.argsort(importances)[::-1]
plt.figure(figsize=(10, 6))
plt.barh(range(len(indices)), importances[indices][::-1])
plt.yticks(range(len(indices)), [X.columns[i] for i in indices[::-1]])
plt.xlabel('特征重要性')
plt.title('哪些特征对房价影响最大?')
plt.tight_layout()
plt.show()
6.2 分类案例:信用卡欺诈检测
python
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import (
classification_report, confusion_matrix,
roc_auc_score, precision_recall_curve
)
from imblearn.over_sampling import SMOTE # 需要 pip install imbalanced-learn
# ─── 模拟不均衡数据(欺诈占比 1%) ───
np.random.seed(42)
n_samples = 10000
n_fraud = int(n_samples * 0.01)
n_normal = n_samples - n_fraud
# 正常交易特征
X_normal = np.random.normal(0, 1, (n_normal, 5))
# 欺诈交易特征(分布不同)
X_fraud = np.random.normal(2.5, 1.5, (n_fraud, 5))
X = np.vstack([X_normal, X_fraud])
y = np.hstack([np.zeros(n_normal), np.ones(n_fraud)])
# 打乱
idx = np.random.permutation(n_samples)
X, y = X[idx], y[idx]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y)
print(f"训练集欺诈占比: {y_train.mean():.3%}")
print(f"测试集欺诈占比: {y_test.mean():.3%}")
# ─── 方法1:不处理不均衡(基准) ───
clf_baseline = LogisticRegression(max_iter=1000)
clf_baseline.fit(X_train, y_train)
y_pred_base = clf_baseline.predict(X_test)
y_prob_base = clf_baseline.predict_proba(X_test)[:, 1]
print("\n=== 基准模型(不处理不均衡)===")
print(classification_report(y_test, y_pred_base, target_names=['正常', '欺诈']))
# ─── 方法2:SMOTE 过采样 ───
smote = SMOTE(random_state=42)
X_train_smote, y_train_smote = smote.fit_resample(X_train, y_train)
print(f"\nSMOTE 后训练集欺诈占比: {y_train_smote.mean():.3%}")
clf_smote = LogisticRegression(max_iter=1000)
clf_smote.fit(X_train_smote, y_train_smote)
y_pred_smote = clf_smote.predict(X_test)
y_prob_smote = clf_smote.predict_proba(X_test)[:, 1]
print("\n=== SMOTE 处理后 ===")
print(classification_report(y_test, y_pred_smote, target_names=['正常', '欺诈']))
# ─── 方法3:调整分类阈值 ───
# 不改变模型,只调整决策阈值以提高召回率
threshold = 0.3 # 降低阈值 → 更多样本被预测为欺诈 → 召回率上升
y_pred_threshold = (y_prob_base >= threshold).astype(int)
print(f"\n=== 阈值调整到 {threshold} ===")
print(classification_report(y_test, y_pred_threshold, target_names=['正常', '欺诈']))
# ─── 最终对比 ───
print("\n=== 综合对比 ===")
print(f"{'方法':<20} {'AUC':>8} {'Recall(欺诈)':>12} {'Precision(欺诈)':>14}")
print("-" * 55)
for name, yp, yprob in [
("基准模型", y_pred_base, y_prob_base),
("SMOTE", y_pred_smote, y_prob_smote),
("阈值0.3", y_pred_threshold, y_prob_base),
]:
auc = roc_auc_score(y_test, yprob)
rec = recall_score(y_test, yp)
prec = precision_score(y_test, yp)
print(f"{name:<20} {auc:>8.4f} {rec:>12.4f} {prec:>14.4f}")
6.3 回归+分类联合:客户终身价值 (LTV) 预测系统
python
# ─── 两阶段模型:先分类(是否付费),再回归(付多少) ───
# 阶段1:分类 --- 预测用户是否会付费
clf = XGBClassifier(n_estimators=100)
clf.fit(X_train, (y_train > 0).astype(int)) # 标签:是否付费
will_pay = clf.predict_proba(X_test)[:, 1] # 付费概率
# 阶段2:回归 --- 仅对付费用户预测金额
payers_mask = y_train > 0
reg = XGBRegressor(n_estimators=100)
reg.fit(X_train[payers_mask], y_train[payers_mask])
predicted_amount = reg.predict(X_test)
# 综合 LTV 预测
ltv_prediction = will_pay * predicted_amount
print(f"预计总 LTV: ¥{ltv_prediction.sum():,.0f}")
print(f"平均每用户 LTV: ¥{ltv_prediction.mean():.2f}")
7. 常见误区与最佳实践
7.1 十大常见误区
| # | 误区 | 真相 |
|---|---|---|
| 1 | 准确率越高越好 | 不均衡数据下,全猜多数类也有高准确率。关注 F1/AUC |
| 2 | 特征越多越好 | 冗余/无关特征引入噪音,增加过拟合风险 |
| 3 | 模型越复杂越好 | 复杂模型需要更多数据,小数据用简单模型 |
| 4 | 训练集表现好就是好模型 | 看验证集/测试集,训练集好可能只是记住答案 |
| 5 | 缺省值直接删掉 | 缺失本身可能是信号;尝试填充或标记 |
| 6 | 不做特征缩放 | 基于距离的模型(SVM、KNN、神经网络)对尺度敏感 |
| 7 | 数据泄露不自知 | 用全量数据做完标准化再划分 → 测试集信息泄露到训练 |
| 8 | R 2 R^2 R2 接近 1 就是好模型 | 可能是过拟合;检查验证集 R 2 R^2 R2 |
| 9 | 线性模型太简单不值得用 | 线性模型可解释性强、训练快,很多场景是首选 baseline |
| 10 | 调参能解决一切 | 数据质量 >> 特征工程 >> 模型选择 >> 调参 |
7.2 项目流程检查清单
□ 1. 明确业务目标(回归/分类?评估指标是什么?)
□ 2. 数据探索 EDA(分布、异常值、缺失值、相关性)
□ 3. 合理划分数据集(时间序列绝不能随机划分)
□ 4. 建立简单 Baseline(线性模型 / 多数类投票)
□ 5. 特征工程(编码、缩放、交互特征、特征选择)
□ 6. 防止数据泄露(先划分再预处理)
□ 7. 尝试多个模型,交叉验证
□ 8. 超参数调优
□ 9. 误差分析(模型在哪些样本上犯错?为什么?)
□ 10. 模型可解释性(SHAP / LIME / 特征重要性)
□ 11. 部署前在留出测试集上最终评估
7.3 速查速记卡
┌─────────────────────────────────────────────┐
│ 回归三剑客 │
│ · 线性回归 --- Baseline,可解释性强 │
│ · 树模型 --- 非线性、特征交互自动捕捉 │
│ · 深度学习 --- 海量数据、复杂模式 │
├─────────────────────────────────────────────┤
│ 分类三剑客 │
│ · 逻辑回归 --- Baseline,概率输出 │
│ · XGBoost --- 表格数据之王 │
│ · 深度学习 --- 图像/文本/序列 │
├─────────────────────────────────────────────┤
│ 不均衡分类三板斧 │
│ · 重采样 (SMOTE / 欠采样) │
│ · 类别权重 (class_weight='balanced') │
│ · 调整决策阈值 │
├─────────────────────────────────────────────┤
│ 防止过拟合四件套 │
│ · 正则化 (L1/L2) │
│ · 交叉验证 │
│ · Early Stopping │
│ · 更多数据 / 数据增强 │
└─────────────────────────────────────────────┘
延伸阅读建议:
- 《统计学习方法》李航 --- 经典理论入门
- 《Hands-On Machine Learning》Géron --- 实战导向
- Kaggle 竞赛 notebook --- 最佳工程实践来源
笔记整理日期:2026-06-16