3、数据预处理与清洗:正则表达式、分词工具(Jieba/Spacy)、停用词过滤、文本标准化
数据预处理,说白了就是给文本「洗澡」。你想想看,从网上扒下来的数据,什么乱七八糟的都有——HTML标签、特殊符号、全角半角混用、错别字……直接扔进模型,它肯定学不会。我刚开始做文本挖掘那会儿,就吃过这个亏。模型训练完一跑,准确率惨不忍睹。后来才发现,是数据里夹杂了一堆「 」和乱码符号。嗯,从那以后,我再也不敢跳过预处理这步了。
核心观点:数据预处理的质量,直接决定了模型的天花板。你后面调参再努力,也弥补不了数据脏乱差带来的损失。
3.1 正则表达式:文本清洗的瑞士军刀
正则表达式,我习惯叫它「正则」。它就像一把手术刀,能精准地从文本中切出你想要的东西,或者切掉你不想要的东西。我个人习惯,拿到文本数据后,第一件事就是写几个正则,把明显的噪音干掉。
常用的正则模式:
\d+:匹配数字\s+:匹配空白字符(空格、换行、制表符)[^\u4e00-\u9fa5a-zA-Z0-9]:匹配非中文、非英文、非数字的字符<.*?>:匹配HTML标签
举个例子,清洗一段带HTML标签的文本:
import re
text = "<p>今天天气<b>真好</b>,适合出去<a href='#'>玩</a>。</p>"
# 去掉所有HTML标签
clean_text = re.sub(r'<.*?>', '', text)
print(clean_text) # 输出:今天天气真好,适合出去玩。
小技巧:正则写完后,一定要用 re.findall() 或 re.sub() 先在小样本上测试一下。我在项目中遇到过,一个看似完美的正则,结果把中文标点也全干掉了,导致句子连成一片,分词都分不出来。
3.2 分词工具:Jieba vs Spacy
分词是中文NLP的基石。英文单词天然有空格分隔,中文可没有。所以,选对分词工具很重要。目前最常用的两个,一个是Jieba,一个是Spacy(中文模型)。
Jieba:轻量、快速、易上手
Jieba是我个人最常用的工具,尤其在做快速原型验证的时候。它支持三种模式:精确模式、全模式、搜索引擎模式。我一般只用精确模式,它切出来的词最干净。
import jieba
text = "我爱自然语言处理"
words = jieba.lcut(text) # 精确模式
print(words) # 输出:['我', '爱', '自然语言', '处理']
Jieba还有一个杀手锏——自定义词典。我在做金融文本挖掘时,经常遇到「量化宽松」「逆回购」这类专业术语。如果不加词典,Jieba会把它们切成「量化」「宽松」。加个自定义词典,一切就对了。
# 自定义词典格式:词 词频 词性
# 量化宽松 5 n
jieba.load_userdict("finance_dict.txt")
words = jieba.lcut("央行实施量化宽松政策")
print(words) # 输出:['央行', '实施', '量化宽松', '政策']
注意:自定义词典的权重很高。如果你加了一个词,Jieba会优先按词典里的切法来。所以,词典里的词一定要准确,别把「机器学习」写成「机器学 习」。
Spacy:工业级、支持多种语言、带依存分析
Spacy的中文模型(zh_core_web_sm)也很不错。它不像Jieba那样只做分词,它还能做词性标注、命名实体识别、依存句法分析。如果你需要做更复杂的文本分析,Spacy是更好的选择。
import spacy
nlp = spacy.load("zh_core_web_sm")
doc = nlp("我爱自然语言处理")
for token in doc:
print(token.text, token.pos_, token.dep_)
不过,Spacy的中文模型比较大,加载速度比Jieba慢。我一般是在做生产级部署时,才会用Spacy。快速实验,还是Jieba更香。
| 对比维度 | Jieba | Spacy(中文) |
|---|---|---|
| 加载速度 | 快(毫秒级) | 慢(秒级) |
| 分词精度 | 高(配合自定义词典) | 高 |
| 功能丰富度 | 仅分词 | 分词+词性+实体+依存 |
| 适用场景 | 快速原型、轻量应用 | 生产级、复杂分析 |
3.3 停用词过滤:去噪的关键一步
停用词,就是那些高频但没啥实际意义的词,比如「的」「了」「在」「是」「一个」。这些词在文本里出现频率极高,但对模型判断文本主题几乎没有贡献。去掉它们,能显著降低特征维度,提升模型效果。
我一般会维护一个停用词表。网上有很多现成的,比如哈工大停用词表、百度停用词表。但我会根据具体任务做调整。比如做情感分析时,「太」「非常」这种程度副词就不能去掉,因为它们对情感强度有影响。
# 加载停用词表
stopwords = set()
with open("stopwords.txt", "r", encoding="utf-8") as f:
for line in f:
stopwords.add(line.strip())
# 过滤停用词
words = ["我", "爱", "自然语言", "处理"]
filtered_words = [w for w in words if w not in stopwords]
print(filtered_words) # 假设"我"在停用词表中,输出:['爱', '自然语言', '处理']
避坑指南:我曾经在做一个电商评论分析项目时,把「不」也加进了停用词表。结果模型把「不好」「不喜欢」都识别成了正面评价,因为「不」被去掉了,只剩下「好」「喜欢」。所以,否定词、程度副词一定要谨慎处理,别一刀切。
3.4 文本标准化:让数据「规规矩矩」
文本标准化,就是把各种「异体」统一成「正体」。比如全角转半角、繁体转简体、大小写统一、数字格式化等。这一步看似简单,但做不好会严重影响后续处理。
常见的标准化操作:
- 全角转半角:中文文本里经常混入全角英文字母和数字,比如「ABC」和「123」。统一转成半角,方便后续处理。
- 繁体转简体:如果你处理的是中文数据,最好统一成简体。我用的是
zhconv库,效果不错。 - 大小写统一:英文部分全部转小写,避免「Apple」和「apple」被当成两个词。
- 数字格式化:把「一万二千三百」转成「12300」,或者统一替换成占位符
<NUM>。
import re
def normalize_text(text):
# 全角转半角
text = text.replace('A', 'A').replace('B', 'B').replace('1', '1')
# 统一小写
text = text.lower()
# 数字替换为占位符
text = re.sub(r'\d+', '<NUM>', text)
return text
print(normalize_text("ABC123测试")) # 输出:abc<NUM><NUM><NUM>测试
个人经验:文本标准化最好放在分词之前做。因为分词工具对全角半角敏感,如果先分词再标准化,可能会把「ABC」切成「A」「B」「C」,而不是一个整体。
3.5 知识体系总览
下面这张图,是我自己总结的数据预处理流程。你可以把它当作一个检查清单,每次做项目时对照着来。
这张图把整个流程串起来了。你从原始文本出发,先做正则清洗,再做标准化,然后分词,最后过滤停用词。每一步都有对应的工具和方法。我个人习惯,每做完一步,都会打印几条样本看看效果,确保没出问题。
好了,数据预处理这块就聊到这儿。记住一句话:垃圾进,垃圾出。你花在数据清洗上的每一分钟,都会在模型训练时加倍回报给你。