命名实体识别基础

好,咱们正式开始聊 NER(Named Entity Recognition)。

什么是 NER?

说白了,就是让机器从文本里找出“谁、哪、什么时候、什么组织”。举个例子:

“2024年3月,辉瑞公司宣布其新冠疫苗有效性达95%。”

NER 要抽出来的实体是:2024年3月(时间)、辉瑞公司(组织)、新冠疫苗(药物/产品)。

我在项目里遇到过最坑的事——中文 NER 里的“药品名”和“疾病名”经常混在一起。比如“阿司匹林”是药,但“阿司匹林哮喘”是个病。分词一旦错了,实体边界就全乱套。所以你想想看,NER 不只是打个标签,它要解决边界识别 + 类别分类两个问题。

评价指标:精确率、召回率、F1 值

这仨指标是 NER 模型好坏的核心。我每次跑完实验第一件事就是看 F1,因为它最能体现综合能力。

指标 含义 公式
精确率 (Precision) 模型预测出的实体中,有多少是真正正确的 TP / (TP + FP)
召回率 (Recall) 所有真实实体中,模型找出了多少 TP / (TP + FN)
F1 值 精确率和召回率的调和平均 2 × P × R / (P + R)

避坑提醒:我曾经在一个药物实体抽取项目里,模型 Precision 冲到 98%,但 Recall 只有 20%——它只挑了最容易的实体,根本不能用。实际场景里宁可 Recall 高一点,漏掉几个好过全吞掉。

计算时通常用 严格匹配(边界和类型都对才算 TP)或 宽松匹配(部分重叠也算)。我建议先跑严格匹配,再看细粒度错误。

一个简单的评估代码片段:

def compute_metrics(y_true, y_pred):
    tp = sum(1 for t, p in zip(y_true, y_pred) if t == p and t != 'O')
    fp = sum(1 for t, p in zip(y_true, y_pred) if t == 'O' and p != 'O')
    fn = sum(1 for t, p in zip(y_true, y_pred) if t != 'O' and p == 'O')
    p = tp / (tp + fp + 1e-8)
    r = tp / (tp + fn + 1e-8)
    f1 = 2 * p * r / (p + r + 1e-8)
    return p, r, f1

经典方法概述

NER 的方法论经历了三代变化。我个人习惯按“规则 → 统计 → 深度学习”的时间线来理解:

类别 代表方法 核心思路 我踩过的坑
规则方法 正则表达式、词典、上下文模板 人工编写模式,匹配固定格式 曾花两周写中药名词典,结果数据里出现“复方丹参滴丸(薄膜衣)”这种变体,词典根本不够用。
统计方法 HMM、CRF、MEMM 用标注数据训练概率模型,CRF 尤其擅长处理标签间的依赖 CRF 特征工程非常痛苦,一个特征忘写就直接掉 5 个点。
深度学习方法 BiLSTM-CRF、BERT + CRF、Transformer 自动学习上下文表示,端到端训练 现在主流方案,但推理速度比规则慢一个数量级。

千万别上来就搞 BERT: 如果数据量连 500 条带标注句子都没有,先试试 CRF + 人工特征,效果往往更好、更可控。

下面这张图展示了从文本到实体的基本流程,也是我经常在项目文档里贴的那张:

典型 NER 方法流程对比 输入文本 规则匹配 正则 / 词典 统计模型 HMM / CRF 深度学习方法 BiLSTM+CRF / BERT 词嵌入 序列标注 CRF 解码 实体列表(类型 + 边界) 统计方法 规则方法 深度学习是当前主流

从图上能看出,规则方法速度快但扩展性差,深度学习精度高但门槛高。我现在的建议是:

  • 冷启动阶段:先用规则产出第一批标注数据,再交给 CRF 迭代。
  • 数据量上万:上 BiLSTM-CRF 或 BERT + CRF,注意平衡训练时间。
  • 生产部署:通常规则 + 模型串联,规则做前置过滤,模型做精排。