文本预处理基础:清洗、分词、词性标注
文本预处理,说白了就是给机器喂饭前,先把菜洗干净、切好。我刚开始做文献抽取的时候,觉得这步可有可无,总想直接上模型。结果呢?模型吃进去一堆乱码和特殊符号,吐出来的结果简直没法看。
后来我才明白:预处理的功夫,直接决定了你后续抽取的质量。今天就把这块的坑和经验都摊开来讲。
3.1 数据清洗——把脏数据洗干净
数据清洗是预处理的第一步。为什么这么重要?你想想看,PDF转出的文本里,常有不可见字符、全角半角混用、多余的换行符。不处理干净,分词和标注全都会跑偏。
我在项目中遇到过最典型的情况:一篇英文论文的摘要里,混着几个中文逗号和句号。分词器直接懵了,把那几个句子当成不同语言混着处理,最后抽取的关键词全是乱的。
常见的清洗操作
- 去除非文本字符:控制字符、零宽空格、Unicode 特殊符号
- 统一大小写:英文全部转小写(除非是专有名词)
- 去除HTML标签:如果你从网页抓取的文献
- 换行符处理:PDF中的硬换行要合并,段落之间保留空行
- 全角/半角统一:数字、字母全部转半角,标点按需处理
我常用的清洗工具是 Python 的 re 和 unicodedata。给个简单的例子:
import re
import unicodedata
def clean_text(text):
# 去除控制字符
text = ''.join(c for c in text if unicodedata.category(c)[0] != 'C' or c == '\n')
# 统一换行:连续2个以上换行视为段落分隔
text = re.sub(r'\n{3,}', '\n\n', text)
# 全角转半角(仅字母数字)
text = unicodedata.normalize('NFKC', text)
return text.strip()
3.2 中文分词——把句子切成词
中文分词,本质就是判断哪些字可以组成一个有意义的词。相比英文天然有空格分隔,中文得靠算法猜。你想想看,"南京市长江大桥"该怎么切?这正是分词的难点。
主流分词工具对比
| 工具 | 特点 | 适用场景 | 速度 |
|---|---|---|---|
| Jieba | 基于词典+统计,支持自定义词典 | 通用场景,入门首选 | 快 |
| HanLP | 基于感知机/CRF,准确率高 | 学术文献、专业术语多的场景 | 中 |
| THULAC | 由清华大学开发,兼顾速度和效果 | 大规模文本处理 | 快 |
| PaddleNLP | 基于预训练模型(ERNIE) | 高精度场景,但对硬件有要求 | 慢 |
我个人习惯用 Jieba 入门。它有个精妙的设计:先根据词典生成有向无环图(DAG),再用动态规划找最大概率路径。核心代码其实很简单:
import jieba
text = "文献抽取中的文本预处理非常重要"
# 精确模式(推荐)
words = jieba.lcut(text)
# ['文献', '抽取', '中', '的', '文本', '预处理', '非常', '重要']
# 添加自定义词典
jieba.add_word('文本预处理')
words = jieba.lcut(text)
# ['文献', '抽取', '中', '的', '文本预处理', '非常', '重要']
Jieba 的分词模式对比
| 模式 | 描述 | 特点 |
|---|---|---|
| 精确模式 | 最精确的分词,无冗余 | 适合文本分析任务 |
| 全模式 | 把所有可能的词都列出来 | 冗余多,但不容易漏词 |
| 搜索引擎模式 | 在精确模式基础上,对长词再切分 | 适合搜索场景 |
3.3 词性标注——给每个词打上标签
分词完,接着给每个词标上词性:名词、动词、形容词……为什么要做?你想想看,"学习"这个词,当动词和当名词时的抽取策略完全不同。
词性标注常用 HMM(隐马尔可夫模型)来做。简单说,就是根据上下文推测最可能的词性序列。Jieba 自带标注功能,咱们直接看:
import jieba.posseg as pseg
text = "深度学习在文献抽取中应用广泛"
words = pseg.lcut(text)
for word, flag in words:
print(f"{word}({flag})", end=' ')
# 深度(n) 学习(vn) 在(p) 文献(n) 抽取(vn) 中(f) 应用(vn) 广泛(a)
| 词性标记 | 含义 | 举例 |
|---|---|---|
| n | 普通名词 | 文献、模型 |
| v | 动词 | 学习、处理 |
| vn | 动名词 | 抽取、分析 |
| a | 形容词 | 广泛、重要 |
| p | 介词 | 在、对 |
标注完成后,你就可以根据词性做过滤了。比如我只保留名词和动名词(因为它们最可能表达领域概念):
def extract_keywords(text):
words = pseg.lcut(text)
keep_flags = ['n', 'vn', 'nz', 'ns']
return [w.word for w in words if w.flag in keep_flags]
本章知识结构
下面这张图总结了文本预处理的完整流程和关键环节:
其实文本预处理没有太多花哨的东西,核心就是三个步骤走扎实:清洗干净、切词准确、标注到位。每一步都有很多细节,但只要你把上面这些基础操作都掌握了,文献抽取的下游工作会顺畅不少。