机器学习应用笔记:回归与分类

理论与实践结合,从数学本质到工程落地

目录

  1. 核心概念:机器学习的本质
  2. [回归分析 Regression](#回归分析 Regression)
  3. [分类任务 Classification](#分类任务 Classification)
  4. [回归 vs 分类:核心对比](#回归 vs 分类:核心对比)
  5. 模型评估与选择
  6. 实战案例
  7. 常见误区与最佳实践

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

相关推荐
秋波。未央6 小时前
Java Agent 开发 · Day 1 学习笔记(含作业完整标准答案)
java·笔记·学习
中屹指纹浏览器6 小时前
2026指纹浏览器字体指纹、字体渲染偏差检测与全维度虚拟字体池搭建方案
经验分享·笔记
FL16238631297 小时前
国内快递面单识别检测数据集VOC+YOLO格式422张6类别
人工智能·yolo·机器学习
codexu_4612291877 小时前
NoteGen 里一条记录如何变成 Markdown
前端·笔记·rust·tauri
cvcode_study7 小时前
Scikit-learn
python·机器学习·scikit-learn
Upsy-Daisy7 小时前
Hermes Agent 学习笔记 10:源码结构与整体架构总结,Hermes 到底是如何运转起来的?
笔记·学习·架构
劈星斩月7 小时前
机器学习之 定义与三大范式
人工智能·机器学习·监督学习·强化学习·无监督学习
Upsy-Daisy8 小时前
Hermes Agent 学习笔记 09:MCP 集成,让 Agent 连接外部工具生态
笔记·学习