NLP学习笔记01:文本预处理详解------从清洗、分词到词性标注
作者:Ye Shun
日期:2026-04-15
一、前言
在自然语言处理(NLP)任务中,模型的效果往往不只取决于算法本身,还和输入数据的质量密切相关。现实中的原始文本通常包含编码混乱、HTML 标签、表情符号、无效字符、格式不统一等问题。如果不先把这些噪声处理掉,后面的分词、建模、分类和生成任务都会受到影响。
因此,文本预处理可以看作 NLP 的第一道关口。它的目标,是把原始的非结构化文本数据,转换成更干净、更规范、更适合机器处理的形式。
这篇笔记围绕三个核心环节展开:
- 文本清洗:去除噪声,让文本"能用"
- 分词:把连续文本切成机器可处理的基本单元
- 词性标注:给词语补充语法角色信息
如果把 NLP 流程比作做饭,那么原始文本就是刚买回来的食材,文本清洗是在洗菜、去杂质,分词是在切菜,词性标注则是在给每一块食材贴上"蔬菜、肉类、调料"的标签。基础处理做得越扎实,后续任务越容易取得稳定效果。
二、文本清洗:净化原始文本数据
文本清洗是文本预处理的第一步,目标是尽可能减少噪声,让后续分析建立在更可靠的数据之上。常见的清洗工作主要包括编码处理、特殊字符处理和无关信息去除。
1. 编码格式处理
不同来源的文本可能使用不同的编码格式,例如 UTF-8、GBK、ASCII 等。如果编码不一致,轻则出现乱码,重则直接报错,导致数据无法读取。
一个简单的编码转换示例如下:
python
# 编码转换示例
text = "示例文本".encode("gbk") # 假设原始编码是 GBK
print(text)
text = text.decode("gbk").encode("utf-8") # 转换为 UTF-8
print(text)
在实际项目中,常见的处理思路有三种:
- 使用
chardet等工具自动检测编码格式 - 统一将文本转换为 UTF-8
- 对无法解码的字符进行替换或忽略
如果数据来源比较杂,比如网页抓取、爬虫文件、不同系统导出的文档,编码处理一定要放在预处理流程最前面。
2. 特殊字符处理
原始文本中常常混有各种特殊字符,例如 HTML 标签、控制字符、表情符号、异常标点等。是否保留它们,要根据任务目标来判断。
常见处理方式如下:
- HTML 标签:通常直接移除,适用于网页文本抓取
- 表情符号:可以删除,也可以映射成情感描述
- 控制字符:一般过滤掉
- 特殊标点:根据场景做标准化处理
例如,去除 HTML 标签可以使用正则表达式:
python
import re
text = "<p>这是一段<b>HTML</b>文本</p>"
clean_text = re.sub(r"<[^>]+>", "", text)
print(clean_text) # 输出:这是一段HTML文本
这里的正则表达式 r"<[^>]+>" 会匹配所有形如 <...> 的标签内容,从而只保留正文文本。
3. 噪声数据去除
除了字符层面的清洗,文本中还可能包含很多和任务无关的噪声信息,例如:
- 广告内容
- 版权声明
- 页脚页眉
- 重复模板句
- 无意义的占位文本
在实际项目里,是否清洗这些内容,要结合任务目标来判断。例如做情感分析时,广告文字可能没有价值;做网页摘要时,导航栏和页脚通常也应该删除。
另外,一些常见的规范化操作也经常出现在这个阶段:
- 统一数字格式,如把
1000规范成1,000 - 统一日期格式,如把
01/01/2023规范成2023-01-01 - 修正常见拼写错误
文本清洗并不是"删得越多越好",而是要有目的地保留信息、移除噪声。
三、分词:把连续文本切成基本单元
分词(Tokenization)是把一段连续文本拆分成若干基本单元(token)的过程。这个步骤非常关键,因为大多数 NLP 模型都不是直接处理整段原始字符串,而是处理分词后的结果。
不同语言的分词难度并不一样。英文有天然的空格边界,而中文没有明显分隔符,因此中文分词通常更复杂。
1. 英文分词
英文分词相对简单,常见做法是基于空格和标点切分。使用 NLTK 可以快速完成英文分词:
python
from nltk.tokenize import word_tokenize
text = "Natural Language Processing is fascinating!"
tokens = word_tokenize(text)
print(tokens)
# ['Natural', 'Language', 'Processing', 'is', 'fascinating', '!']
不过,英文分词并不是简单的 split() 就能完全处理好的,还需要注意以下细节:
- 缩写形式,如
I'm、don't - 专有短语,如
New York - 连字符结构,如
state-of-the-art - 标点符号是否保留
在教学场景下,NLTK 很适合入门;在工程实践中,也常见使用 spaCy 等更高效的工具。
2. 中文分词
中文没有空格作为天然分隔,因此中文分词本质上更接近一个"切词决策"问题。常见方法可以分为三类:
- 基于词典的方法:如最大匹配法
- 基于统计的方法:如 HMM、CRF
- 基于深度学习的方法:如 BiLSTM-CRF、BERT
在学习和实践中,jieba 是最常见、最容易上手的中文分词工具。例如:
python
import jieba
text = "自然语言处理非常有趣"
tokens = jieba.lcut(text)
print(tokens)
# ['自然语言', '处理', '非常', '有趣']
中文分词的难点在于歧义切分和新词识别。比如一句话可能有多种切法,不同语境下结果也会不一样。因此在实际应用中,经常需要:
- 加入自定义词典
- 调整领域词汇
- 针对特定任务优化切分策略
3. 子词分词
在深度学习模型中,除了"按词切分",还有一种非常重要的方法叫子词分词(Subword Tokenization)。它主要用来解决两个问题:
- 罕见词处理困难
- 词表过大带来的存储和训练压力
常见子词分词方法包括:
- BPE(Byte Pair Encoding)
- WordPiece
- Unigram Language Model
以 Hugging Face 中的 BERT 中文分词器为例:
python
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained("bert-base-chinese")
tokens = tokenizer.tokenize("自然语言处理")
print(tokens)
# ['自', '然', '语', '言', '处', '理']
可以看到,在某些预训练模型中,中文并不总是按完整词切分,而是可能拆成更细粒度的子词甚至单字。这种方式更适合神经网络模型处理,也能更好覆盖未登录词。
4. 常用分词工具简单对比
常见工具可以粗略理解为:
NLTK:英文处理经典工具,适合教学和基础实验spaCy:工业级 NLP 工具,速度快,适合实际项目jieba:中文分词入门首选,简单易用,支持自定义词典Stanford CoreNLP:功能全面,准确率较高,但资源开销较大HuggingFace Tokenizers:适合深度学习与预训练模型场景
工具没有绝对优劣,关键是看任务需求、语言类型和性能要求。
四、词性标注:给词语添加语法角色
词性标注(Part-of-Speech Tagging,POS Tagging)是为每个词语标注其语法类别的过程,例如"名词、动词、形容词、副词"等。它能帮助模型更好理解句子结构,也是很多高级 NLP 任务的重要基础。
1. 为什么要做词性标注
词性标注的价值主要体现在三个方面:
- 帮助理解句子结构
- 缓解词义歧义
- 为句法分析、信息抽取、命名实体识别等任务提供支持
例如,同一个词在不同上下文中可能扮演不同角色。如果只看词本身,模型容易误解;而词性信息则能提供额外线索。
2. 常见词性体系
不同语言和工具会采用不同的标签体系。
英文中常见的是 Penn Treebank 标签集,例如:
NN:名词VB:动词JJ:形容词RB:副词PRP:代词
中文里常见的是 ICTCLAS 风格标签,例如:
n:名词v:动词a:形容词d:副词r:代词
理解标签体系并不要求全部死记,但至少要知道常见标签大致代表什么,否则看到结果也很难解读。
3. 自动词性标注方法
从方法上看,词性标注大致经历了三类路线:
- 基于规则的方法:依赖人工规则
- 基于统计的方法:如 HMM、最大熵模型
- 基于深度学习的方法:如 RNN、Transformer
不同方法的核心目标都一样,就是根据上下文判断每个词最可能属于什么词性。
4. 词性标注示例
使用 spaCy 可以对英文文本进行词性标注:
python
import spacy
nlp = spacy.load("en_core_web_sm")
doc = nlp("Natural Language Processing is fascinating!")
for token in doc:
print(token.text, token.pos_)
如果处理中文,也可以使用 jieba.posseg 进行分词和词性标注:
python
import jieba.posseg as pseg
words = pseg.cut("自然语言处理很有趣")
for word, flag in words:
print(word, flag)
这种方式很适合作为入门学习,因为可以直接看到每个词对应的词性标签。
5. 词性标注的评估指标
评价词性标注效果时,常见指标包括:
- 准确率(Accuracy)
- 未登录词准确率(OOV Accuracy)
- 混淆矩阵分析
其中,未登录词表现通常更能反映模型的泛化能力,因为模型对训练中没见过的词往往更难判断。
五、实践中的预处理顺序建议
在大多数文本处理任务中,可以按如下顺序进行:
- 编码处理
- 文本清洗
- 分词
- 词性标注
这个顺序的原因很自然:如果编码还没统一,文本就可能读不对;如果文本里还充满 HTML 标签和噪声字符,分词结果也会受到干扰;而词性标注又依赖分词结果,因此必须放在后面。
除了流程顺序,实践中还要注意以下几点:
- 根据任务目标决定清洗力度,不要机械删除所有符号
- 针对专业领域建立自定义词典,如医学、法律、金融
- 对大规模数据集考虑并行化和批处理
- 不同工具的输出格式不完全一致,最好统一封装
六、结合本次代码的一个完整演示思路
下面给出一个更适合学习演示的处理流程。它包含:
- 编码转换示例
- HTML 清洗
- 英文简易分词
- 中文分词与词性标注
python
import re
try:
import jieba.posseg as pseg
except ImportError:
pseg = None
def encoding_demo():
text = "示例文本".encode("gbk")
print("GBK 编码结果:", text)
utf8_text = text.decode("gbk").encode("utf-8")
print("UTF-8 编码结果:", utf8_text)
def remove_html_tags(text):
return re.sub(r"<[^>]+>", "", text)
def process_english(text):
tokens = re.findall(r"[A-Za-z]+(?:'[A-Za-z]+)?|[^\w\s]", text)
print("英文分词:", tokens)
def process_chinese(text):
if pseg is None:
print("未安装 jieba,无法进行中文分词和词性标注。")
return
print("中文分词 + 词性标注:")
for word, flag in pseg.cut(text):
print(f"{word} : {flag}")
print("=== 编码处理 ===")
encoding_demo()
print("\n=== HTML 清洗 ===")
html_text = "<p>这是一段<b>HTML</b>文本</p>"
print(remove_html_tags(html_text))
print("\n=== 英文处理 ===")
process_english("Natural Language Processing is fascinating!")
print("\n=== 中文处理 ===")
process_chinese("自然语言处理很有趣")
相比简单地直接调用多个库,这种写法更适合作为学习笔记保存,因为每一步都比较清晰,也更方便后续扩展。
七、总结
文本预处理虽然常被看作 NLP 中最基础的部分,但它实际上决定了后续任务的输入质量。编码处理解决"能不能正确读取"的问题,文本清洗解决"数据干不干净"的问题,分词解决"如何切分基本单元"的问题,词性标注则进一步补充了语法结构信息。
从学习路径上看,建议先把这三个步骤真正理解透,再去学文本分类、情感分析、命名实体识别和大模型相关内容。因为越往后走,越会发现很多模型效果问题,最后都能追溯到最前面的数据处理是否合理。