4. 多标签识别基础

在金融公告场景中,我们经常遇到一条公告同时涉及多个业务含义的情况。例如一份《关于回购股份并注销的公告》,既属于“股份回购”,又涉及“注册资本变更”,还可能触发“公司治理”标签。如果把它强行归入唯一类别,就会丢失关键信息。这正是多标签识别要解决的核心问题。

一、核心原理:多标签与多分类的本质区别

多分类(Multi-class Classification)假设样本属于且仅属于一个类别,类别之间互斥。例如把公告分为“定期报告、临时公告、中介报告”三类,一条公告只能落在一个类别中。多标签(Multi-label Classification)则允许一个样本同时拥有多个标签,标签之间可以共存、可以相关,也可以相互独立。

从数学形式看,多分类的输出是一个概率分布,所有类别概率之和为1;多标签的输出是每个标签独立的概率值,通常对每个标签做二分类判断。因此,多标签问题常被转化为“标签数量个二分类问题”,或使用多标签神经网络输出多个Sigmoid节点。

关键判断:如果业务上一条样本只能有一个答案,用多分类;如果一条样本可以同时命中多个答案,且这些答案都需要保留,就必须用多标签。

在金融公告中,多标签的典型来源包括:一份公告同时涉及“担保”和“关联交易”;一份年报同时包含“业绩预告”和“分红送转”;一份监管问询回复同时涉及“信息披露”和“合规风险”。这些标签并非互斥,而是从不同维度描述同一文本。

二、标签相关性:多标签问题的难点所在

多标签识别不是简单地把多个二分类器拼在一起。标签之间往往存在统计相关性和语义相关性,忽略它们会显著降低效果。

  • 正相关:“股份回购”与“股价稳定”经常同时出现;“关联交易”与“关联方”高度共现。
  • 负相关:“业绩预增”与“业绩预亏”通常不会同时出现;“终止重组”与“重组进展”在时间上互斥。
  • 层级相关:“定期报告”是父标签,“年报”“半年报”“季报”是子标签,子标签命中时父标签通常也应命中。
  • 条件相关:“控制权变更”出现时,“实际控制人变更”的概率会显著上升。

处理标签相关性的常见策略有三类:一是问题转换法,如分类器链(Classifier Chain),把前一个标签的预测结果作为后一个标签的特征;二是算法适应法,如多标签K近邻、多标签决策树;三是深度学习方法,通过共享底层表示并联合训练多个标签输出,让模型自动学习标签间依赖。

多分类 vs 多标签:输出结构与标签相关性 多分类:互斥单选 输入:一份公告文本 输出:仅一个类别 例:定期报告 / 临时公告 / 中介报告 概率之和 = 1,类别互斥 多标签:可多选共存 输入:一份公告文本 输出:多个标签同时为真 例:股份回购 + 注册资本变更 + 公司治理 各标签独立判断,可相关 对比

三、评价指标:不能只看准确率

多标签场景下,普通准确率(Accuracy)会严重失真。因为标签数量多、正例稀疏,模型全部预测为“无标签”也可能获得很高的准确率。因此必须使用专门的多标签指标。

指标含义适用场景
Hamming Loss预测错误的标签比例,越小越好整体标签级错误率评估
Micro-F1把所有标签的TP/FP/FN汇总后计算F1标签分布不均衡时更稳健
Macro-F1先算每个标签F1,再取平均关注稀有标签表现
Subset Accuracy预测标签集合与真实集合完全一致才算对要求严格匹配的场景
mAP平均精度均值,考虑排序质量标签排序与阈值选择

实践建议:金融公告多标签任务中,优先看Micro-F1和Macro-F1的组合。Micro-F1反映整体效果,Macro-F1暴露稀有标签是否被模型忽略。若两者差距过大,说明模型偏向高频标签,需要做重采样或损失加权。

四、典型应用与误区复盘

多标签识别在金融公告中的典型应用包括:公告主题多标签打标、风险事件多维度识别、监管问询要点抽取、研报事件驱动标签体系、舆情与合规联合监测。例如一条公告可以同时打上“并购重组”“停牌”“关联交易”“业绩承诺”四个标签,供下游检索、风控和投研使用。

常见误区主要有四个:

  1. 把多标签当多分类做。用Softmax输出多分类,导致只能选一个标签,召回率大幅下降。
  2. 忽略标签相关性。独立训练多个二分类器,没有利用“回购”与“股价稳定”的共现关系,效果受限。
  3. 只看准确率。标签稀疏时准确率虚高,掩盖了模型对正例的漏判。
  4. 阈值一刀切。所有标签都用0.5阈值,高频标签和低频标签的最优阈值往往不同,应基于验证集分别调优。
# 多标签输出层示例(PyTorch)
import torch.nn as nn

class MultiLabelClassifier(nn.Module):
    def __init__(self, input_dim, num_labels):
        super().__init__()
        self.fc = nn.Linear(input_dim, num_labels)

    def forward(self, x):
        logits = self.fc(x)
        return torch.sigmoid(logits)  # 每个标签独立概率

# 损失函数:BCEWithLogitsLoss
criterion = nn.BCEWithLogitsLoss()

复盘提醒:多标签任务中,标签体系设计比模型选择更关键。标签定义模糊、边界重叠、层级混乱,会让标注一致性和模型效果同时恶化。建议先固定标签字典和互斥规则,再进入建模阶段。