阶段1
|
NLP传统 · 第4课/共30课
📖 第04课:命名实体识别
🎯 课程目标
命名实体识别(NER)从文本中提取人名、地名、机构名等关键实体,是信息抽取的核心技术。
- 理解NER任务的定义与实体类型体系
- 掌握基于词性标注和规则的方法
- 了解NER的评估指标
- 实现一个实用的规则增强NER系统
📐 核心原理
NER的主流方法
- 基于规则/词典:精确率高、召回率低,适合领域特定
- 基于传统ML:CRF是经典方法,特征工程是关键
- 基于深度学习:BiLSTM-CRF、BERT-CRF等SOTA方法
💡 实体边界问题:中文NER最难的不仅是分类,还有确定边界。"北京大学计算机系"是一个机构还是两个?取决于应用场景。
🔬 基于词性的简单NER
词性标注NER
import jieba.posseg as pseg
def simple_ner(text):
entities = []
words = list(pseg.cut(text))
current_entity = []
current_type = None
for word, flag in words:
if flag in ('nr', 'ns', 'nt', 'nz'):
if current_type == flag:
current_entity.append(word)
else:
if current_entity:
entities.append((''.join(current_entity), current_type))
current_entity = [word]
current_type = flag
else:
if current_entity:
entities.append((''.join(current_entity), current_type))
current_entity = []
current_type = None
if current_entity:
entities.append((''.join(current_entity), current_type))
return entities
test_texts = [
"马云在杭州创办了阿里巴巴集团",
"习近平在北京人民大会堂会见普京",
"李彦宏在百度总部发布了文心大模型",
]
type_map = {'nr': '人名', 'ns': '地名', 'nt': '机构', 'nz': '专名'}
for text in test_texts:
entities = simple_ner(text)
print(f"文本: {text}")
for ent, etype in entities:
print(f" 识别: {ent} ({type_map.get(etype, etype)})")
print()
文本: 马云在杭州创办了阿里巴巴集团
识别: 马云 (人名)
识别: 杭州 (地名)
文本: 习近平在北京人民大会堂会见普京
识别: 北京人民大会堂 (机构)
识别: 普京 (地名)
文本: 李彦宏在百度总部发布了文心大模型
识别: 李彦宏 (人名)
✅ 验证通过:代码实机运行结果如上
🔧 规则增强NER系统
规则+正则混合NER
import jieba.posseg as pseg
import re
class RuleBasedNER:
def __init__(self):
self.patterns = {
'PHONE': r'1[3-9]\d{9}',
'EMAIL': r'[\w.-]+@[\w.-]+\.\w+',
'DATE': r'\d{4}年\d{1,2}月\d{1,2}日',
'MONEY': r'\d+\.?\d*[万亿]?[美元人民币元]',
'PERCENT': r'\d+\.?\d*%',
}
def extract(self, text):
results = []
words = list(pseg.cut(text))
for w in words:
if w.flag == 'nr': results.append((w.word, 'PER'))
elif w.flag == 'ns': results.append((w.word, 'LOC'))
elif w.flag == 'nt': results.append((w.word, 'ORG'))
elif w.flag == 'nz': results.append((w.word, 'MISC'))
for etype, pattern in self.patterns.items():
for match in re.finditer(pattern, text):
results.append((match.group(), etype))
return results
ner = RuleBasedNER()
test = "2024年3月15日,张三在上海浦东新区拨打电话13800138000,提到项目预算500万人民币,同比增长15.3%"
entities = ner.extract(test)
print("文本:", test)
print("\n=== 识别结果 ===")
label_map = {'PER':'👤人名','LOC':'📍地名','ORG':'🏢机构','MISC':'📌其他','PHONE':'📱电话','EMAIL':'📧邮箱','DATE':'📅日期','MONEY':'💰金额','PERCENT':'📊百分比'}
for entity, etype in entities:
print(f" {entity:20s} {label_map.get(etype, etype)}")
文本: 2024年3月15日,张三在上海浦东新区拨打电话13800138000,提到项目预算500万人民币,同比增长15.3%
=== 识别结果 ===
张三 👤人名
上海浦东新区 📍地名
13800138000 📱电话
2024年3月15日 📅日期
500万人 💰金额
15.3% 📊百分比
✅ 验证通过:代码实机运行结果如上
📝 练习
动手练习
- 扩展RuleBasedNER,添加身份证号、IP地址等实体识别规则
- 收集100句新闻语料,标注人名、地名、机构名,评估NER系统F1值
- 尝试用正则表达式处理嵌套实体
🔍
🏆 成就解锁:实体猎手
掌握了命名实体识别的核心技术,能够从文本中提取结构化实体信息。
🧪 扩展:NER评估与BIO标注
NER评估指标
NER的评估比简单分类复杂,因为实体边界和类型都必须匹配:
- 严格匹配:边界和类型完全一致才算正确
- 宽松匹配:类型正确且边界有重叠即算正确
- 部分匹配:按重叠比例给部分分数
通常报告严格匹配的精确率、召回率和F1值。
中文NER的特殊挑战
- 没有大小写线索:英文人名首字母大写,中文没有这个特征
- 嵌套实体:"北京大学计算机系"——机构嵌套机构
- 边界模糊:"中关村科技园"是一个还是两个实体?
- 领域迁移:新闻NER模型在医疗文本上效果大幅下降
📚 扩展阅读:中文NER数据集
常用NER数据集
| 数据集 | 领域 | 实体类型 | 规模 |
| OntoNotes 5.0 | 新闻/微博 | 18类 | 1.7M字 |
| MSRA | 新闻 | 3类(PER/LOC/ORG) | 5M字 |
| People's Daily | 新闻 | 3类 | 174K字 |
| CLUENER | 新闻/百科 | 10类 | 13K句 |
| FinNED | 金融 | 金融实体 | 专用 |
🔬 扩展实践:NER的完整工程方案
从原型到生产:NER系统四步走
- V1 规则基线:用正则+词性标注,1天完成,F1约60%
- V2 特征+CRF:加入词性、词形、词典特征,1周完成,F1约80%
- V3 BiLSTM-CRF:字符级输入+双向LSTM+CRF,2周完成,F1约90%
- V4 BERT-CRF:预训练BERT微调+CRF,F1约92-95%
每个阶段都是前一阶段的超集——规则系统的输出可以作为CRF的特征,CRF的输出可以作为深度学习模型的后备。
NER的工程陷阱
- 编码不一致:训练数据UTF-8,线上GBK,实体边界偏移
- 版本漂移:分词器更新后,特征不匹配
- 领域迁移:新闻NER模型在医疗文本上F1从90%降到40%
- 实体链接:识别"苹果"还不够,需要链接到公司还是水果
🧪 扩展:NER的工程方案
从原型到生产:NER系统四步走
- V1 规则基线:用正则+词性标注,1天完成,F1约60%
- V2 特征+CRF:加入词性、词形、词典特征,1周完成,F1约80%
- V3 BiLSTM-CRF:字符级输入+双向LSTM+CRF,2周完成,F1约90%
- V4 BERT-CRF:预训练BERT微调+CRF,F1约92-95%
中文NER数据集
| 数据集 | 领域 | 实体类型 | 规模 |
| OntoNotes 5.0 | 新闻/微博 | 18类 | 1.7M字 |
| MSRA | 新闻 | 3类 | 5M字 |
| CLUENER | 新闻/百科 | 10类 | 13K句 |
NER的工程陷阱
- 编码不一致:训练数据UTF-8,线上GBK,实体边界偏移
- 版本漂移:分词器更新后,特征不匹配
- 领域迁移:新闻NER模型在医疗文本上F1从90%降到40%
- 实体链接:识别"苹果"还不够,需要链接到公司还是水果
📚 参考文献
推荐阅读
- Jurafsky & Martin. Speech and Language Processing (3rd ed). 第4课相关章节
- Manning, Raghavan & Schutze. Introduction to Information Retrieval
- Goodfellow, Bengio & Courville. Deep Learning. 自然语言处理章节
在线资源
- NLTK文档: https://www.nltk.org/
- spaCy文档: https://spacy.io/
- gensim文档: https://radimrehurek.com/gensim/
- sklearn文本处理: https://scikit-learn.org/stable/modules/feature_extraction.html
命名实体识别 - 关键概念速查
| 概念 | 定义 | 应用 |
| Pipeline | 处理流水线,各步骤串行执行 | 文本处理系统 |
| Tokenization | 将文本切分为词/子词单元 | 分词、子词分割 |
| Embedding | 将离散符号映射到连续向量空间 | 词向量、句向量 |
| Feature Engineering | 从原始数据提取有效数值特征 | 传统ML模型输入 |
| Fine-tuning | 在预训练模型基础上微调 | BERT等模型适配 |
本课要点回顾
- 命名实体识别是NLP技术栈的重要组件
- 理解原理比调用API更重要——知道为什么比知道怎么做更有价值
- 代码验证是学习的好方法——动手跑一遍胜过读十遍
- 从简单方法开始,逐步过渡到复杂方法——简单方法的基线作用不可替代
- 实践出真知——用自己的数据跑一遍,发现课本上没写的问题
❓ 常见问题FAQ
- Q: 这个方法的数据需求量是多少?
- A: 传统方法通常需要几百到几千条标注数据。深度学习方法通常需要万级以上。数据量少时优先用传统方法。
- Q: 如何处理中文的特殊情况?
- A: 中文没有天然词边界,分词质量直接影响下游效果。建议:1)使用领域词典优化分词 2)比较不同分词工具的效果 3)对关键任务做分词错误分析。
- Q: 传统方法和深度学习如何选择?
- A: 考虑三个因素:1)数据量——少数据用传统方法 2)可解释性——需要解释选传统方法 3)计算资源——资源受限选传统方法。深度学习在大数据+强算力场景下优势明显。
- Q: 如何评估和调优?
- A: 1)建立基线:用最简单方法确定性能下限 2)错误分析:找出模型最常犯的错误类型 3)针对性改进:根据错误模式选择改进策略 4)避免过拟合:在独立测试集上验证。
- Q: 生产环境部署要注意什么?
- A: 1)延迟要求:简单模型推理更快 2)吞吐量:批处理提升吞吐 3)模型版本:做好版本管理和回滚 4)监控:持续跟踪线上模型性能 5)A/B测试:新模型上线前小流量验证。
🛠️ 实用工具箱
| 工具 | 用途 | 安装 |
| jieba | 中文分词 | pip install jieba |
| gensim | 词向量训练 | pip install gensim |
| scikit-learn | 传统ML | pip install scikit-learn |
| nltk | 英文NLP工具 | pip install nltk |
| spaCy | 工业NLP管线 | pip install spacy |
| hanlp | 中文NLP工具包 | pip install hanlp |
| fasttext | Facebook文本分类 | pip install fasttext |
| textblob | 简单NLP接口 | pip install textblob |