文本预处理基础:清洗、标准化、分词前处理

很多人一上来就直接搞分词、跑模型,结果模型学出来的东西乱七八糟。我早期也踩过这个坑——数据还没洗干净就喂给模型,输出全是噪音。说白了,文本预处理就是给机器“喂饭”前的洗菜切菜环节。你想想看,菜都没洗干净的厨师能做出好菜吗?

为什么文本预处理如此关键

原始文本里全是“杂质”:HTML标签、特殊符号、大小写混乱、不统一的全角半角、拼写错误……机器可不像我们人眼一样能自动过滤这些。举个例子,“I'm fine” 和 “i am fine” 在语义上一样,但如果不做大小写统一和缩写展开,模型就会把它们当成两个不同的,白白浪费资源。

核心原则:预处理的目标是保留语义信息,去掉非信息噪音。千万不要过度清洗把有用的结构也删掉了。

文本清洗:去除噪音

清洗是第一道关卡。常见的噪音包括:

  • HTML/XML标签:网页抓取来的文本常带 <p>、<br> 等,需要正则或专用库(如BeautifulSoup)剥离。
  • 特殊字符和Emoji:比如 @、#,或者大量重复的标点 !!!。我个人习惯保留句号、问号等基本标点,但去掉连续重复的符号。
  • URL和邮箱:通常替换为特殊标记如 [URL],或者直接移除。
  • 非ASCII字符:如果是英文任务,把全角字符转成半角;中文任务则保留中文标点。

小技巧:清洗的正则表达式尽量写严谨,别把语言本身的缩写或标点(如 can't 里的单引号)也删了。我曾经因为一刀切规则把 "it's" 清洗成了 "its",语义完全变了。

文本标准化:统一格式

标准化就是把各种“变体”拉回到一个统一的表现形式。常见操作:

操作说明示例
大小写统一英文全部转小写(大多数情况)“Hello” → “hello”
缩写展开“don’t” → “do not”需注意上下文,避免过度展开
数字处理数字替换为 <NUM> 或保留原样“123” → “<NUM>”
词形还原/词干提取“running” → “run” (词干) 或 “run” (词形还原)词干更激进,词形还原保留合法词
全半角转换全角字母和数字转为半角“A” → “A”

这里要注意顺序。我习惯先做大小写统一,再做缩写展开,因为某些缩写依赖小写识别。

分词前处理:为分词铺路

把文本喂给分词器之前,还有几步不能少:

  1. 去除多余空格和换行符:连续的空白符压缩成一个空格。
  2. 句子分割:把长文本拆成句子,很多分词器对跨句的分词效果不好。
  3. 编码统一:确保所有字符都是UTF-8,避免出现奇奇怪怪的乱码。
  4. 语种识别(可选):如果数据集混有多种语言,需要先分语种处理。

你可能觉得“压缩空格”这种小动作无所谓?错。我曾经处理一批英文新闻,原文里到处都是连续空格,结果分词器把空白本身也当成了,产生了一堆空字符串。清掉之后,词表大小直接降了15%。

实践:一个完整的预处理流水线

下面是我惯用的Python流水线片段,配合 re 和 nltk:

import re
from nltk.tokenize import word_tokenize

def clean_text(text):
    # 去除HTML标签
    text = re.sub(r'<.*?>', '', text)
    # 去除URL
    text = re.sub(r'https?://\S+', ' [URL] ', text)
    # 统一小写
    text = text.lower()
    # 展开常见缩写(简化版)
    text = re.sub(r"don't", "do not", text)
    text = re.sub(r"can't", "cannot", text)
    # 压缩空格
    text = re.sub(r'\s+', ' ', text).strip()
    return text

raw = "I can't believe <b>that</b> cost $100!!"
cleaned = clean_text(raw)
tokens = word_tokenize(cleaned)
print(tokens)  # ['i', 'cannot', 'believe', 'that', 'cost', '$', '100', '!', '!']

你看,这个例子保留了符号 $ 和连续感叹号——如果你的任务不需要情感分析,或许要去掉后者。所以预处理一定要根据你的下游任务灵活调整。

常见陷阱与避坑指南

⚠️ 踩坑预警:

  • 过度去除标点:比如对于情感分析,感叹号 ! 是重要特征,去掉会降低准确率。
  • 词干提取滥用:“better” 的词干是 “better”,但词形还原可能给出 “good”,两者差异很大。
  • 大小写如果用于命名实体识别,就不能直接全部小写,因为 “Apple” 公司名和 “apple” 水果需要区分。
  • 忘记处理编码错误:我曾经遇到过 \xe2\x80\x99 这种弯单引号,直接扔给分词器会报 UnicodeDecodeError。

嗯,预处理看起来琐碎,但做扎实了,能省掉后续模型调参时的无数烦恼。记住:垃圾进,垃圾出。你花在清洗上的每一分钟,都会在模型性能上得到回报。

文本预处理知识体系 原始文本 文本清洗 文本标准化 分词前处理 去HTML标签 去特殊符号 去URL/邮箱 大小写统一 缩写展开 词形还原 压缩空白符 句子分割 编码统一 干净标准化的文本 原则:保留语义,去除噪音