AI 工程基础体系 · 第 52/100 篇。内容覆盖机器学习、深度学习与生成式 AI;模型、数据、评测、权限和成本会作为同一生产系统处理。

不平衡学习:采样、代价敏感、指标、阈值与概率校准

不平衡学习(imbalanced learning)处理的是这样的分类问题:不同类别的样本数量、错误代价或决策收益并不对称。欺诈检测中,欺诈可能只占全部交易的千分之一;医学筛查中,阳性病例可能很少,但漏诊代价很高;内容审核中,违规样本比例会随事件、地区和策略变化。

“不平衡”至少包含三种不同含义:

  1. 类别比例不平衡:正负样本数量不同。
  2. 错误代价不平衡:假阴性和假阳性的损失不同。
  3. 决策资源不平衡:模型筛出的样本需要人工审核、拦截或额外计算,而可用资源有限。

这三者经常同时存在,但解决方式不同。增加少数类样本不能自动表达业务代价;选择更高召回率也不能自动得到可信概率;模型准确率很高也不能说明系统可用。


先固定问题:标签、概率、动作和代价

设二分类标签为:

Y{0,1}Y\in\{0,1\}

模型接收特征 XX,输出一个分数。这个分数可能是:

  • 硬分类结果Y^{0,1}\hat{Y}\in\{0,1\}
  • 排序分数:用于把样本从高风险排到低风险;
  • 概率估计p^(X)\hat p(X),希望接近[
    P(Y=1\mid X)
    ]。

这三种输出不能混为一谈。一个模型可以排序能力很好,却概率不准;也可以概率校准良好,但在当前阈值下召回率不满足业务要求。

最终系统通常还要选择动作 AA,例如:

  • 放行;
  • 拒绝;
  • 进入人工审核;
  • 触发更昂贵的模型;
  • 要求用户补充验证。

因此完整链路是:

X模型分数或概率阈值/策略AX \rightarrow \text{模型分数或概率} \rightarrow \text{阈值/策略} \rightarrow A

训练模型主要学习前两步,阈值和策略负责后两步。把训练、评测、阈值和校准混成一个步骤,是不平衡任务中最常见的设计错误之一。


混淆矩阵:所有分类指标的起点

对二分类结果,定义混淆矩阵:

实际/预测 预测负类 预测正类
实际负类 TN,真负例 FP,假正例
实际正类 FN,假负例 TP,真正例

其中:

  • TP:正确识别的正类;
  • TN:正确识别的负类;
  • FP:把负类错判为正类;
  • FN:把正类错判为负类。

常用指标为:

Accuracy=TP+TNTP+TN+FP+FN\text{Accuracy}=\frac{TP+TN}{TP+TN+FP+FN}

Precision=TPTP+FP\text{Precision}=\frac{TP}{TP+FP}

Recall=TPR=TPTP+FN\text{Recall}=\text{TPR}=\frac{TP}{TP+FN}

Specificity=TNR=TNTN+FP\text{Specificity}=\text{TNR}=\frac{TN}{TN+FP}

Precision 也称查准率,回答“预测为正的样本中有多少是真的”;Recall 也称召回率或灵敏度,回答“所有正样本中找出了多少”。

一个准确率具有欺骗性的例子

假设有 10,000 个交易,其中只有 100 个欺诈交易。模型把全部交易都预测为正常:

  • TN=9,900TN=9,900
  • FN=100FN=100
  • TP=0TP=0
  • FP=0FP=0

此时:

Accuracy=99%\text{Accuracy}=99\%

但:

Recall=0\text{Recall}=0

如果业务目标是发现欺诈,这个模型实际上没有完成任务。

再看另一个模型:

  • TP=80TP=80
  • FN=20FN=20
  • FP=20FP=20
  • TN=9,880TN=9,880

则:

Precision=8080+20=80%\text{Precision}=\frac{80}{80+20}=80\%

Recall=8080+20=80%\text{Recall}=\frac{80}{80+20}=80\%

Accuracy=80+988010000=99.6%\text{Accuracy}=\frac{80+9880}{10000}=99.6\%

准确率仍然很高,但它不再是主要信息。此时应同时关心 80% 的召回率、20 个误报以及每个误报和漏报的业务代价。


类别比例与基准概率

令正类先验概率为:

π=P(Y=1)\pi=P(Y=1)

在欺诈检测中,π\pi 可能是 0.001;在疾病筛查中,它可能是 0.02。类别比例会直接影响 Precision,即使模型的 TPR 和 FPR 完全不变。

设:

TPR=P(Y^=1Y=1)\text{TPR}=P(\hat{Y}=1\mid Y=1)

FPR=P(Y^=1Y=0)\text{FPR}=P(\hat{Y}=1\mid Y=0)

根据全概率公式:

P(Y^=1)=πTPR+(1π)FPRP(\hat{Y}=1)=\pi\cdot\text{TPR}+(1-\pi)\cdot\text{FPR}

因此:

Precision=πTPRπTPR+(1π)FPR\text{Precision} = \frac{\pi\cdot\text{TPR}} {\pi\cdot\text{TPR}+(1-\pi)\cdot\text{FPR}}

这说明了一个关键事实:当正类非常稀少时,即使 FPR 很低,FP 仍然可能多于 TP。

例如:

  • π=0.001\pi=0.001
  • TPR = 0.90
  • FPR = 0.01

则:

Precision=0.001×0.90.001×0.9+0.999×0.018.3%\text{Precision} = \frac{0.001\times0.9} {0.001\times0.9+0.999\times0.01} \approx 8.3\%

模型找到了 90% 的正类,但每 100 个告警中只有约 8 个是真的。这个结果不一定无用,因为人工审核成本、漏报损失和误报损失还没有纳入;但它说明不能从 Recall 单独推断系统质量。


采样:改变训练分布,而不是创造信息

欠采样和过采样

常见采样方法包括:

  • 随机欠采样:减少多数类样本;
  • 随机过采样:重复少数类样本;
  • 合成过采样:例如 SMOTE,在少数类样本之间插值生成新样本;
  • 批次重采样:深度学习训练时,让每个 batch 含有更高比例的少数类。

它们的核心作用是改变训练时不同类别对损失函数的贡献,而不是增加新的真实信息。

如果原始数据中:

  • 负类 9,900 个;
  • 正类 100 个;

随机过采样正类到 1,000 个后,模型在训练中看到的正类比例提高了,但这 900 个新增样本通常只是原有样本的重复。它可能改善优化过程,也可能导致模型过拟合少数类。

采样必须只发生在训练数据

错误流程是:

  1. 先对全部数据过采样;
  2. 再切分训练集和验证集。

如果重复样本的原件和副本分别进入训练集、验证集,验证集就不再独立。模型可能“记住”样本,而不是学习可泛化规律。

正确流程是:

  1. 先按用户、设备、时间或样本进行训练/验证/测试切分;
  2. 只对训练集采样;
  3. 验证集和测试集保持接近真实生产分布;
  4. 在真实分布上评估指标、阈值和概率。

如果一个用户有多笔交易,通常不能让同一用户同时出现在训练和测试中,否则用户特征会造成泄漏。时间相关任务还应优先使用按时间切分,避免用未来数据预测过去。

SMOTE 的边界

SMOTE 对两个少数类样本 xi,xjx_i,x_j 做插值:

xnew=xi+λ(xjxi),λ[0,1]x_{\text{new}}=x_i+\lambda(x_j-x_i),\quad \lambda\in[0,1]

它隐含了一个假设:少数类样本之间的线性插值仍然有意义。这个假设在连续数值特征上有时合理,但在以下场景可能失败:

  • 类别编码被当成连续数值;
  • 文本或稀疏高维向量的线性插值没有自然语义;
  • 少数类包含多个互不相连的子群;
  • 特征之间存在严格业务约束;
  • 时间序列样本不能随意插值。

因此,SMOTE 不是“生成真实正例”的通用方法。对文本、图像和深度模型,通常需要使用任务特定的数据增强,并验证增强样本是否保持标签语义。

采样改变了什么

采样主要改变:

  • 类别在训练目标中的相对权重;
  • 优化器看到各类别的频率;
  • 模型对决策边界的偏好;
  • 输出分数的概率解释。

采样通常不会改变:

  • 原始问题的真实正类比例;
  • 测试集的真实业务分布;
  • 标签噪声;
  • 特征是否包含可预测信息。

最后一点很重要:如果正类本身没有可区分的特征,过采样只能重复噪声。


代价敏感学习:直接把错误写进目标函数

代价敏感学习(cost-sensitive learning)不改变样本本身,而是为不同错误指定权重。

设模型输出 fθ(x)f_\theta(x),单个样本损失为 (fθ(x),y)\ell(f_\theta(x),y),则加权经验风险为:

R^(θ)=1ni=1nwyi(fθ(xi),yi)\hat R(\theta) = \frac{1}{n} \sum_{i=1}^{n} w_{y_i}\ell(f_\theta(x_i),y_i)

其中 w0,w1w_0,w_1 分别是负类和正类权重。

在逻辑回归中,未加权目标可写成:

i[yilogpi+(1yi)log(1pi)]-\sum_i \left[ y_i\log p_i+(1-y_i)\log(1-p_i) \right]

加权后为:

i[w1yilogpi+w0(1yi)log(1pi)]-\sum_i \left[ w_1y_i\log p_i+ w_0(1-y_i)\log(1-p_i) \right]

正类权重更大时,模型会更重视减少正类损失,通常会提高正类召回率,但也可能增加误报。

权重与重复采样的关系

在许多可加和损失中,给一个样本权重 kk,与把这个样本重复 kk 次,在目标函数层面近似等价:

ki=i+i++ik 次k\ell_i = \underbrace{\ell_i+\ell_i+\cdots+\ell_i}_{k\text{ 次}}

但在实际训练中不一定完全等价,因为:

  • mini-batch 的组成不同;
  • batch normalization 的统计量不同;
  • dropout 和随机增强不同;
  • 优化器的梯度更新时序不同;
  • 过采样可能让模型反复记忆样本。

因此,“class weight 等于过采样”是目标函数层面的近似,而不是训练行为完全相同。

权重不应机械地等于类别倒数

常见做法是令:

wc1ncw_c\propto\frac{1}{n_c}

它可以让类别在总损失中获得类似贡献,但并不代表业务上最优。若漏掉一个正类的代价远高于误报,权重可能应更高;若人工审核容量有限,权重又不能无限增大。

训练权重应区分两个来源:

  1. 统计平衡权重:为了避免多数类主导梯度;
  2. 业务代价权重:为了表达错误成本。

两者可以同时存在,但需要明确乘积关系,否则很容易无意中把正类权重放大数十甚至数百倍。


代价、阈值与贝叶斯决策

假设模型输出的是校准概率:

p=P(Y=1X=x)p=P(Y=1\mid X=x)

定义:

  • CFPC_{\text{FP}}:预测为正但实际为负的代价;
  • CFNC_{\text{FN}}:预测为负但实际为正的代价;
  • 暂时假设正确分类代价为 0。

选择正类时,期望代价为:

L(positivex)=CFP(1p)L(\text{positive}\mid x) = C_{\text{FP}}(1-p)

选择负类时,期望代价为:

L(negativex)=CFNpL(\text{negative}\mid x) = C_{\text{FN}}p

选择正类当且仅当:

CFP(1p)<CFNpC_{\text{FP}}(1-p)<C_{\text{FN}}p

整理得:

p>CFPCFP+CFNp> \frac{C_{\text{FP}}} {C_{\text{FP}}+C_{\text{FN}}}

所以理论阈值是:

t=CFPCFP+CFNt^*= \frac{C_{\text{FP}}} {C_{\text{FP}}+C_{\text{FN}}}

若漏报代价是误报的 9 倍,即 CFN=9CFPC_{\text{FN}}=9C_{\text{FP}},则:

t=11+9=0.1t^*=\frac{1}{1+9}=0.1

这不是说“模型概率超过 0.1 就一定应该拦截”。它成立的前提是:

  • 概率确实校准;
  • 代价估计可靠;
  • 每个样本的代价相同;
  • 没有人工审核、容量限制和多阶段动作;
  • 当前数据分布与概率对应的分布一致。

代价矩阵扩展

如果正确分类也有收益或代价,应比较完整的条件期望损失:

E[L(a,Y)X=x]=pL(a,1)+(1p)L(a,0)\mathbb{E}[L(a,Y)\mid X=x] = pL(a,1)+(1-p)L(a,0)

对多个动作,如放行、拦截、人工审核,可分别计算期望损失,选择最小者。人工审核动作还应加入审核费用、延迟和容量限制。

当人工审核每天最多处理 KK 个样本时,问题不再是每个样本独立使用固定阈值,而可能是:

  1. 先按风险概率排序;
  2. 取前 KK 个进入审核;
  3. 其余样本按另一条策略处理。

此时“阈值”可能由流量和容量共同决定,并会随日流量变化。


指标:根据任务选择,而不是寻找万能分数

ROC 曲线与 AUC

ROC 曲线以:

  • 横轴:FPR;
  • 纵轴:TPR;

展示阈值变化时的性能。ROC-AUC 衡量排序能力:随机抽取一个正类和一个负类时,模型把正类排在负类之前的概率。

AUC 是阈值无关的排序指标,但它不直接告诉你生产中该使用哪个阈值,也不包含具体审核容量和错误代价。

在极低正类比例下,ROC 曲线可能看起来很好,因为 FPR 的小幅变化在比例上很小,但绝对误报数仍然很多。

Precision-Recall 曲线与平均精确率

PR 曲线以 Recall 为横轴、Precision 为纵轴,更直接反映正类稀少时的告警质量。随机分类器的 Precision 基线大致等于正类比例 π\pi,因此同一个 PR-AUC 在不同数据集上的含义不能脱离基线比较。

例如正类比例从 1% 变为 0.1%,即使模型的排序机制完全不变,Precision 也可能显著下降。

F1 与 F-beta

F1 是 Precision 和 Recall 的调和平均:

F1=2PRP+RF_1= \frac{2PR}{P+R}

调和平均会惩罚其中一个指标很低的情况。

F-beta 为:

Fβ=(1+β2)PRβ2P+RF_\beta = (1+\beta^2) \frac{PR}{\beta^2P+R}

  • β>1\beta>1:更重视 Recall;
  • β<1\beta<1:更重视 Precision。

F1 隐含了相对对称的取舍,并不等于真实业务成本最小。若审核员的工作量有硬上限,Precision@K、Recall@K 或 Top-K 告警命中率可能比 F1 更直接。

其他指标的适用边界

  • Balanced Accuracy

    TPR+TNR2\frac{\text{TPR}+\text{TNR}}{2}

    对两类分别平均,适合类别比例不均衡但错误代价近似对称的情况。
  • MCC:综合四个混淆矩阵元素,在极不平衡情况下通常比 Accuracy 更稳定,但仍然是固定阈值指标。
  • Specificity:筛查中常用于约束误报。
  • Recall@固定误报率:安全、审核和检测场景常用。
  • Precision@K / Recall@K:人工审核容量有限时适用。
  • 对数损失和 Brier score:评估概率质量,而不仅是类别决策。

二分类中的 Brier score 为:

Brier=1ni=1n(p^iyi)2\text{Brier} = \frac{1}{n} \sum_{i=1}^{n}(\hat p_i-y_i)^2

它越小越好。它同时受到概率校准和区分能力影响,不能只把它当作校准误差。

多分类和多标签

多分类中,少数类的整体指标可能被多数类掩盖,应同时报告:

  • macro average:先分别计算每类指标,再平均;
  • weighted average:按各类样本数加权;
  • 每类 one-vs-rest 的 Recall、Precision 和 PR-AUC;
  • 混淆矩阵。

macro 指标能显示小类表现,但方差可能很大;weighted 指标更接近总体样本体验,却可能隐藏少数类失败。

多标签任务中,一个样本可同时属于多个标签,应按标签统计,并明确 micro、macro 和样本级指标的含义。一个全局阈值未必适合所有标签,因为每个标签的先验概率和错误代价可能不同。


阈值:模型训练完成后仍然可以改变决策

设模型输出连续分数 s(x)s(x)。阈值 tt 产生:

y^={1,s(x)t0,s(x)<t\hat y= \begin{cases} 1,&s(x)\ge t\\ 0,&s(x)<t \end{cases}

改变阈值不会改变已经训练好的排序分数,但会改变 TP、TN、FP、FN,进而改变 Precision、Recall、F1 和业务成本。

因此,下面两种说法不同:

  • “模型的 Recall 是 80%”:必须说明阈值和数据分布;
  • “模型 ROC-AUC 是 0.92”:描述的是跨阈值排序能力。

阈值选择的正确数据流

阈值不能在测试集上反复试到最好。合理流程是:

  1. 训练集拟合模型;
  2. 验证集选择阈值、代价策略或 Top-K 规则;
  3. 测试集只做一次最终报告;
  4. 上线后在独立时间窗口验证。

如果训练过程、超参数搜索和阈值搜索都使用同一验证集,验证结果会逐渐过拟合。数据量允许时,可以使用嵌套交叉验证,或者保留一个最终测试集。

阈值与 class weight 的关系

class weight 会改变模型训练出的分数分布和决策边界。若加权交叉熵训练后直接使用 0.5 阈值,通常不能解释为“真实概率超过 50%”。

即使模型排序更好,也可能需要:

  • 在真实分布验证集上重新选阈值;
  • 对概率进行校准;
  • 或使用先验修正后再按业务代价决策。

“把正类权重调高”与“把阈值调低”在某些简单模型上可能产生相似的分类结果,但它们不是同一个操作:

  • 权重改变训练目标和表示;
  • 阈值只改变最终动作;
  • 权重还可能改变排序、泛化和概率质量。

概率校准:分数是否能被当成概率

概率校准要求:对所有输出约为 0.7 的样本,实际正类比例也应接近 0.7。

形式化地说,理想校准满足:

P(Y=1p^(X)=p)=pP(Y=1\mid \hat p(X)=p)=p

例如模型给出 1,000 个“风险 0.8”的样本,若其中约 800 个最终为正类,则该区间近似校准;若只有 300 个为正类,模型就是过度自信。

区分能力与校准能力

一个模型可以:

  • 排序正确,但所有概率都偏高;
  • 概率平均正确,但排序能力一般;
  • 经过过采样后在采样分布上看似合理,却不符合生产先验。

AUC 主要评价排序;校准曲线、Brier score 和 Log Loss 更关注概率质量。两者应分别评估。

可靠性图

将预测概率分桶,例如:

  • [0.0, 0.1)
  • [0.1, 0.2)
  • [0.9, 1.0]

对每个桶计算:

  • 横坐标:桶内平均预测概率;
  • 纵坐标:桶内实际正类比例;
  • 参考线:y=xy=x

曲线在参考线上方表示模型低估风险,在下方表示模型高估风险。样本很少的高概率桶方差可能很大,因此还应报告每个桶的样本量或置信区间。

常见校准方法

Platt scaling / sigmoid 校准

用一个逻辑函数把原始分数映射为概率:

p^=σ(as+b)\hat p=\sigma(as+b)

其中 a,ba,b 在独立校准数据上拟合。它参数少,通常比较稳定,但只能表达较平滑的映射。

Isotonic regression

学习一个单调非递减函数:

p^=g(s)\hat p=g(s)

它不要求 sigmoid 形状,数据量足够时更灵活;数据量较小时容易过拟合。

温度缩放

深度分类模型常用:

pk=exp(zk/T)jexp(zj/T)p_k= \frac{\exp(z_k/T)} {\sum_j\exp(z_j/T)}

其中 zkz_k 是 logit,TT 是在校准集上学习的温度。它主要调整置信度尖锐程度,不改变类别排序。

校准方法必须使用没有参与基础模型训练的数据。若在训练集上校准,模型和校准器可能共同过拟合,线上概率会失真。


采样后的概率为什么会失真

这是不平衡学习中最容易被忽略的推导。

设真实生产先验为:

π=P(Y=1)\pi=P(Y=1)

采样后训练数据中的先验为:

πs=Ps(Y=1)\pi_s=P_s(Y=1)

模型在采样分布上输出:

q(x)=Ps(Y=1X=x)q(x)=P_s(Y=1\mid X=x)

根据 Bayes 定理:

q(x)1q(x)=Ps(X=xY=1)Ps(X=xY=0)πs1πs\frac{q(x)}{1-q(x)} = \frac{P_s(X=x\mid Y=1)} {P_s(X=x\mid Y=0)} \cdot \frac{\pi_s}{1-\pi_s}

假设采样只改变类别比例,不改变类条件分布:

Ps(XY)=P(XY)P_s(X\mid Y)=P(X\mid Y)

真实概率 p(x)p(x) 的 odds 为:

p(x)1p(x)=P(X=xY=1)P(X=xY=0)π1π\frac{p(x)}{1-p(x)} = \frac{P(X=x\mid Y=1)} {P(X=x\mid Y=0)} \cdot \frac{\pi}{1-\pi}

两式相除可得:

p(x)1p(x)=q(x)1q(x)π/(1π)πs/(1πs)\frac{p(x)}{1-p(x)} = \frac{q(x)}{1-q(x)} \cdot \frac{\pi/(1-\pi)} {\pi_s/(1-\pi_s)}

也就是:

p(x)=r(x)1+r(x)p(x) = \frac{r(x)}{1+r(x)}

其中:

r(x)=q(x)1q(x)π/(1π)πs/(1πs)r(x)= \frac{q(x)}{1-q(x)} \cdot \frac{\pi/(1-\pi)} {\pi_s/(1-\pi_s)}

数值例子

真实正类比例为 1%,采样后正类比例为 50%。某样本在采样分布下的预测概率为 q=0.8q=0.8

采样分布 odds:

q1q=0.80.2=4\frac{q}{1-q}=\frac{0.8}{0.2}=4

先验修正因子为:

0.01/0.990.5/0.50.0101\frac{0.01/0.99}{0.5/0.5} \approx0.0101

所以真实 odds 约为:

4×0.0101=0.04044\times0.0101=0.0404

转换回概率:

p0.04041.04043.88%p\approx\frac{0.0404}{1.0404}\approx3.88\%

也就是说,在平衡采样数据上看似 80% 的风险,在真实 1% 先验下可能只有约 3.9%。这不是模型“突然失效”,而是模型回答了另一个分布下的概率问题。

该修正依赖于类条件分布没有被采样破坏。如果生产数据发生概念漂移、采样机制依赖特征,或过采样生成了不同分布的数据,仅靠先验修正不够,必须在真实分布校准集上重新校准。


一个可运行的 scikit-learn 示例

下面的示例展示四件事:

  1. 在不平衡数据上训练;
  2. class_weight 表达训练阶段的类别权重;
  3. 用验证集选择 F1 最优阈值;
  4. CalibratedClassifierCV 在交叉验证中校准概率。
import numpy as np
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.calibration import CalibratedClassifierCV
from sklearn.metrics import (
    average_precision_score,
    classification_report,
    confusion_matrix,
    f1_score,
    brier_score_loss,
)

# 固定随机种子,便于复现
X, y = make_classification(
    n_samples=20_000,
    n_features=20,
    n_informative=8,
    n_redundant=2,
    weights=[0.99, 0.01],
    flip_y=0.01,
    random_state=42,
)

# 先切分,再进行任何只应作用于训练数据的处理
X_train, X_tmp, y_train, y_tmp = train_test_split(
    X, y, test_size=0.4, stratify=y, random_state=42
)
X_valid, X_test, y_valid, y_test = train_test_split(
    X_tmp, y_tmp, test_size=0.5, stratify=y_tmp, random_state=42
)

# class_weight 只影响训练损失;它不改变验证集和测试集的类别比例
base_model = LogisticRegression(
    max_iter=1000,
    class_weight="balanced",
    solver="lbfgs",
    random_state=42,
)

# 使用训练集内部交叉验证拟合校准器。
# 这里的 estimator 参数适用于当前 scikit-learn 版本的常见 API。
model = CalibratedClassifierCV(
    estimator=base_model,
    method="sigmoid",
    cv=5,
)
model.fit(X_train, y_train)

# 在真实比例的验证集上选择阈值
valid_prob = model.predict_proba(X_valid)[:, 1]
candidate_thresholds = np.linspace(0.01, 0.99, 197)

scores = [
    f1_score(y_valid, valid_prob >= t)
    for t in candidate_thresholds
]
best_threshold = float(candidate_thresholds[int(np.argmax(scores))])

# 测试集只使用已经确定的阈值
test_prob = model.predict_proba(X_test)[:, 1]
test_pred = test_prob >= best_threshold

print("positive rate:", y_test.mean())
print("best threshold:", best_threshold)
print("average precision:", average_precision_score(y_test, test_prob))
print("brier score:", brier_score_loss(y_test, test_prob))
print(confusion_matrix(y_test, test_pred))
print(classification_report(y_test, test_pred, digits=4))

输入是人为生成的、正类比例约为 1% 的数据。stratify=y 使切分后的类别比例大致稳定,但它不能处理用户级泄漏或时间泄漏;真实交易数据仍应根据业务主键和时间切分。

class_weight="balanced" 是 scikit-learn 的常见实现,用训练集中的类别频率自动设置权重。它不是业务成本矩阵的完整表达。若正类漏报代价有明确金额,应在验证集上按金额或期望损失选择阈值,而不是只优化 F1。

代码中的 CalibratedClassifierCV 使用交叉验证生成校准所需的非训练预测,避免直接用基础模型对其训练样本校准。不同 scikit-learn 版本对参数名称可能存在变化,运行前应以安装版本的 API 文档和 help(CalibratedClassifierCV) 为准;这里不依赖实验性接口。

average_precision 反映 PR 排序质量,brier_score_loss 反映概率误差。最终混淆矩阵和分类报告则是在选定阈值下的动作结果。它们分别回答不同问题,不能互相替代。


深度学习中的不平衡处理

深度学习中常见的手段包括:

加权交叉熵

二分类加权交叉熵可写为:

[w1ylogp+w0(1y)log(1p)]-\left[ w_1y\log p+w_0(1-y)\log(1-p) \right]

实现上通常通过每个样本的 weight 或类别权重传入损失函数。需要检查框架对 reduction 的定义:mean 可能是普通平均,也可能是按权重重新归一化的平均,二者会影响梯度规模。

Focal loss

Focal loss 常写为:

αt(1pt)γlog(pt)-\alpha_t(1-p_t)^\gamma\log(p_t)

其中:

  • ptp_t 是真实类别对应的预测概率;
  • αt\alpha_t 是类别权重;
  • γ\gamma 控制对易分类样本的降权程度。

当样本很容易被正确分类时,(1pt)γ(1-p_t)^\gamma 较小,损失集中于难例。Focal loss 可能提升少数类识别,但它优化的是关注难例的目标,并不保证输出概率天然校准,训练后通常仍需在真实分布校准集上验证。

Batch 组成和归一化层

如果每个 batch 都被强制平衡,模型训练看到的类别比例可能与生产完全不同。对于依赖 batch 统计的归一化层,改变 batch 构成还可能改变内部统计量。因此应单独验证:

  • 平衡 batch 是否改善少数类召回;
  • 是否损害真实分布下的 Precision;
  • 推理阶段概率是否需要重新校准。

失败模式与诊断方法

只看 Accuracy

表现:准确率很高,正类 Recall 接近 0。

诊断:查看混淆矩阵、正类 Recall、PR 曲线和正类基线。

修复方向:先确认任务目标,再调整损失、采样或阈值;不要直接把 Accuracy 换成某个单一指标。

过采样后验证结果异常好

表现:验证集指标远高于线上,或相邻样本在训练与验证中高度相似。

诊断:检查切分顺序、重复样本、用户/设备/文档 ID 是否跨集合,检查增强是否在切分前执行。

修复方向:先按独立实体或时间切分,再只对训练集采样。

class weight 提高后 Precision 崩溃

表现:Recall 上升,但告警数量激增,人工审核队列溢出。

原因:训练目标更偏向正类,并不等于业务系统能处理更多告警。

诊断:绘制阈值—Recall—Precision—告警量—总成本曲线。

修复方向:保留训练权重用于学习,再在真实分布验证集上选择阈值;必要时使用 Top-K 或人工审核动作。

采样后概率明显偏高

表现:模型输出大量 0.8、0.9,但对应区间真实正类比例很低。

原因:模型学习的是采样后的先验,或者加权损失改变了概率解释。

诊断:在未经采样的时间外验证集上绘制可靠性图,计算 Brier score 和分桶实际率。

修复方向:用真实分布校准集进行 sigmoid、isotonic 或温度缩放;若已知且满足条件,也可先做先验 odds 修正。

在测试集上选择阈值

表现:离线测试分数很好,但换时间窗口后大幅下降。

原因:测试集被用于策略搜索,报告值已经包含了选择偏差。

修复方向:验证集选择阈值,测试集只做最终确认;上线前模拟未来时间窗口。

把 PR-AUC 当作业务收益

表现:PR-AUC 提升,但人工审核成本或漏报损失上升。

原因:PR-AUC 汇总了多个阈值,没有体现审核上限、单次错误金额和延迟。

修复方向:同时报告固定审核量下的 Precision/Recall、固定 FPR 下的 Recall,以及成本函数。


生产系统中的数据流与状态

不平衡分类系统不只是一个模型文件。一个可审计的生产链路通常如下:

flowchart LR
    A[原始事件] --> B[特征构造]
    B --> C[模型输出分数/概率]
    C --> D[概率校准]
    D --> E[版本化决策策略]
    E --> F{动作}
    F --> G[放行]
    F --> H[拦截]
    F --> I[人工审核]
    H --> J[反馈与标签]
    I --> J
    G --> J
    J --> K[延迟标签评估]
    K --> L[指标/校准/漂移监控]
    L --> M[重新训练或调整阈值]

关键状态包括:

  • 事件状态:样本是否已接收、特征是否完整;
  • 决策状态:采用了哪个模型、校准器和阈值版本;
  • 审核状态:是否进入队列、是否超时、是否人工改判;
  • 标签状态:真实标签是否已到达,是否仍是未知;
  • 监控状态:当前正类比例、告警率、校准误差是否异常。

标签常常延迟到达。例如欺诈可能在数周后才确认,内容申诉也可能晚于模型决策。不能把尚未确认的样本直接当成负类,否则会系统性低估 FN。

并发和故障也会影响指标。人工审核队列满时,系统可能降级为自动放行;特征服务超时时,模型可能使用默认值;重复事件重试时,可能产生重复告警。这些行为会改变实际 FP、FN 和成本,因此应在决策日志中保存:

  • 样本或事件 ID;
  • 特征时间和决策时间;
  • 模型版本;
  • 校准器版本;
  • 阈值或策略版本;
  • 原始分数与最终概率;
  • 实际动作;
  • 降级原因;
  • 最终标签及标签时间。

权限也属于模型系统的一部分。训练人员不应默认能够读取全部敏感标签;审核人员需要查看作出判断所需的证据,但不一定需要访问完整原始特征。权限变化可能改变可用特征和标签覆盖率,进而造成看似“模型漂移”的数据变化。


分布变化、先验变化与重新校准

不平衡任务尤其容易受到正类比例变化影响。要区分:

仅先验变化

类条件分布近似不变,但正类比例改变:

Pnew(XY)Pold(XY)P_{\text{new}}(X\mid Y)\approx P_{\text{old}}(X\mid Y)

此时模型排序可能仍然可用,但概率和 Precision 会变化。可以考虑先验修正或在新分布校准。

协变量变化

特征分布 P(X)P(X) 变化,但条件关系可能近似稳定。这会改变分数分布和告警量,需要检查特征漂移与分桶性能。

概念变化

P(YX)P(Y\mid X)

发生变化,例如攻击者改变行为。此时旧模型的排序、概率和阈值都可能失效,单纯重新校准通常不够,需要重新训练或改进特征。

监控不能只看总体 Accuracy。应按时间、地区、产品、用户类型和风险分层报告:

  • 正类率;
  • 告警率;
  • Precision、Recall;
  • 固定流量下的命中率;
  • 概率分桶校准误差;
  • 标签延迟;
  • 每个动作的成本;
  • 模型和规则的覆盖率。

当真实标签尚未到达时,可以暂时监控输入漂移、输出分布和告警量,但这些不是最终性能指标,不能替代延迟标签评估。


生成式 AI 场景中的不平衡问题

生成式 AI 系统同样会遇到不平衡学习,只是分类器可能位于不同位置:

  • 内容安全分类器中,违规样本通常稀少;
  • RAG 检索器中,真正相关的文档相对全部候选很少;
  • 工具调用意图识别中,危险动作是少数但代价很高;
  • 生成结果质量评估中,严重错误样本低频但影响大;
  • 审核和拒答策略中,不同政策标签的比例差异很大。

例如,安全分类器若把“违规”设为正类,不能只看总体准确率。应分别评估:

  • 高风险类别的 Recall;
  • 误伤正常内容的 FPR;
  • 每千次请求的人工审核量;
  • 风险概率是否可解释;
  • 不同语言、地区和内容类型的分层校准;
  • 模型拒答、放行和升级审核的成本。

生成式系统还存在级联成本:先用小模型筛选,再调用大模型审核。此时阈值不仅决定 FP/FN,还决定大模型调用次数和 GPU 成本。一个看似提升 Recall 的阈值,如果让绝大多数请求进入昂贵模型,可能使单位请求成本不可接受。

对于 RAG,候选文档中的相关文档通常是少数。Recall@K 衡量是否把相关文档召回,Precision@K 衡量候选集合的噪声;生成答案的最终正确率还受到重排、提示和生成模型影响,不能用检索器单独的 Accuracy 代替。


如何把训练、评测和决策连起来

一个完整的不平衡学习实验至少应明确以下对象:

  1. 真实评估分布:测试集是否代表生产分布;
  2. 训练处理:是否采样、加权或使用特殊损失;
  3. 模型输出含义:是排序分数还是概率;
  4. 校准数据:是否独立于基础模型训练;
  5. 阈值规则:按成本、F-beta、固定 FPR 还是 Top-K;
  6. 容量约束:人工审核和额外推理资源上限;
  7. 最终指标:混淆矩阵、PR、校准和成本是否同时报告;
  8. 时间窗口:标签延迟和分布变化是否被纳入;
  9. 版本记录:模型、采样策略、校准器和阈值是否可回溯。

核心因果关系可以概括为:

  • 采样和类别权重主要改变训练目标;
  • 模型分数主要用于排序和区分;
  • 概率校准使分数更接近真实事件概率;
  • 阈值和策略把概率转换为动作;
  • 指标和成本评价动作是否符合目标;
  • 生产分布、容量、权限和推理成本决定离线结果能否转化为系统结果。

因此,不平衡学习不是简单地“让少数类更多”或“把阈值调低”。真正可靠的方案必须同时回答:模型能否区分、概率是否可信、错误代价是什么、系统能处理多少告警,以及这些结论在未来数据和真实权限边界下是否仍然成立。


系列导航与关联阅读

官方资料

本文依据研究论文、标准组织与主流框架官方文档重新梳理;正文、示例与工程清单由 WR BLOG 编写。