3. 文本预处理实战:中文分词、去停用词、词性标注、文本清洗全流程
文本预处理,说白了就是给原始文本「洗澡」。
我刚开始做量化舆情分析时,拿到的新闻数据简直惨不忍睹——乱码、特殊符号、英文夹杂、还有一堆「的」「了」「吗」这种没用的词。如果不处理干净,后面建模就是垃圾进垃圾出。
这一章,咱们就把整个预处理流水线走一遍。我会带着你从原始文本一步步走到干净、可用的特征向量。
3.1 文本清洗:先把脏东西筛掉
文本清洗是第一步,也是最容易被忽略的一步。我见过不少新手直接拿原始文本去分词,结果模型效果差得离谱。
清洗的核心目标就三个:
- 去噪:去掉HTML标签、URL、特殊符号、乱码字符
- 统一格式:全角转半角、繁体转简体、统一大小写
- 过滤无效内容:去掉过短文本、重复文本、纯数字文本
避坑指南:我曾经在清洗阶段把「ST股票」中的「ST」当成英文单词给删了,结果模型完全识别不了ST股的风险信号。所以清洗规则一定要结合业务场景来定。
下面是我常用的清洗函数:
import re
import unicodedata
def clean_text(text):
# 1. 全角转半角
text = unicodedata.normalize('NFKC', text)
# 2. 去掉HTML标签
text = re.sub(r'<.*?>', '', text)
# 3. 去掉URL
text = re.sub(r'http[s]?://\S+', '', text)
# 4. 保留中文、英文、数字、基本标点
text = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9,。!?、;:""''()【】《》\s]', '', text)
# 5. 合并多余空格
text = re.sub(r'\s+', ' ', text).strip()
return text
小技巧:清洗时别一刀切。比如「+5%」中的百分号对量化分析很重要,我一般会保留「%」「+」「-」这几个符号。
3.2 中文分词:把句子切成词
中文不像英文有空格分隔,所以分词是中文NLP的基石。你想想看,「金融市场」到底是「金融/市场」还是「金融市/场」?分错了意思就全变了。
目前主流的分词工具有三个:
| 工具 | 速度 | 准确率 | 适用场景 |
|---|---|---|---|
| jieba | 快 | 中等 | 通用场景、快速原型 |
| pkuseg | 中等 | 高 | 金融、医学等专业领域 |
| HanLP | 慢 | 很高 | 需要词性标注、命名实体识别 |
我个人习惯用 jieba + 自定义词典 的组合。为什么?因为金融领域有大量专业术语,比如「量化宽松」「逆回购」「北向资金」,这些词默认词典里没有。
import jieba
# 加载自定义金融词典
jieba.load_userdict('finance_dict.txt')
# 示例:金融词典内容
# 量化宽松 5
# 逆回购 5
# 北向资金 5
# ST股票 3
text = "央行今日开展逆回购操作,释放流动性"
words = jieba.lcut(text)
print(words)
# 输出:['央行', '今日', '开展', '逆回购', '操作', ',', '释放', '流动性']
注意:自定义词典的权重不要乱设。我踩过坑——把「涨停」设为高频词,结果「涨停板」被切成了「涨停/板」,反而错了。一般设3-5就够了。
3.3 去停用词:扔掉没用的词
停用词就是那些高频但没实际意义的词,比如「的」「了」「在」「是」「一个」。这些词在情感分析里基本不贡献信息量,留着反而增加噪声。
我常用的停用词表包含三类:
- 通用停用词:的、了、在、是、我、你、他、这、那
- 金融领域停用词:报告、显示、表示、指出、据悉
- 标点符号:,。!?、;:""''()【】《》
def load_stopwords(path='stopwords.txt'):
with open(path, 'r', encoding='utf-8') as f:
return set([line.strip() for line in f])
stopwords = load_stopwords()
def remove_stopwords(words):
return [w for w in words if w not in stopwords and len(w) > 1]
# 示例
words = ['央行', '今日', '开展', '逆回购', '操作', ',', '释放', '流动性']
filtered = remove_stopwords(words)
print(filtered)
# 输出:['央行', '今日', '开展', '逆回购', '操作', '释放', '流动性']
经验之谈:我一般会保留单字词中的「涨」「跌」「多」「空」——这些字在金融文本里信息量极大,不能一刀切去掉。
3.4 词性标注:给每个词打标签
词性标注就是告诉程序:这个词是名词、动词还是形容词。在量化情绪建模里,词性标注有两个重要作用:
- 提取情感词:形容词和副词往往是情感信号(如「大幅上涨」「严重亏损」)
- 过滤噪声:去掉虚词、连词、助词
我用的是 jieba 自带的词性标注功能,配合 paddle 模式准确率更高:
import jieba.posseg as pseg
# 使用Paddle模式(需要安装paddlepaddle)
jieba.enable_paddle()
text = "A股三大指数今日集体收涨"
words = pseg.cut(text, use_paddle=True)
for word, flag in words:
print(f'{word}/{flag}', end=' ')
# 输出:A股/n 三大/m 指数/n 今日/t 集体/n 收涨/v
词性标注的标签含义:
| 标签 | 含义 | 示例 |
|---|---|---|
| n | 名词 | 股票、指数、市场 |
| v | 动词 | 上涨、下跌、买入 |
| a | 形容词 | 强劲、低迷、稳健 |
| d | 副词 | 大幅、持续、明显 |
| t | 时间词 | 今日、昨日、本周 |
核心思路:在情感分析中,我通常只保留 a(形容词)、d(副词)、v(动词)这三类,因为它们承载了大部分情感信息。名词和时间词可以视情况保留。
3.5 全流程整合:一条流水线搞定
好了,现在我们把所有步骤串起来。这是我实际项目中用的预处理流水线:
def preprocess_pipeline(text):
# 1. 清洗
text = clean_text(text)
# 2. 分词 + 词性标注
words_with_pos = pseg.cut(text, use_paddle=True)
# 3. 过滤:只保留形容词、副词、动词
keep_flags = {'a', 'd', 'v'}
filtered = [(w.word, w.flag) for w in words_with_pos
if w.flag in keep_flags and len(w.word) > 1]
# 4. 去停用词
filtered = [(w, f) for w, f in filtered if w not in stopwords]
# 5. 返回词列表
return [w for w, f in filtered]
# 测试
text = "今日A股三大指数集体收涨,市场情绪明显回暖"
result = preprocess_pipeline(text)
print(result)
# 输出:['收涨', '明显', '回暖']
你看,原始文本有11个词,经过流水线后只剩下3个核心情感词。这就是预处理的威力——把噪声去掉,让信号更清晰。
3.6 本章知识体系
下面这张图展示了整个文本预处理的流程和关键决策点:
嗯,到这里文本预处理的完整流程就讲完了。你可能会问:为什么非要把流程拆这么细?
原因很简单——每个步骤都可能引入错误。清洗阶段漏了特殊符号,分词阶段切错了词,停用词表删了关键信息……任何一个环节出问题,后面的模型都会跟着跑偏。
我建议你在实际项目中,每一步都输出中间结果看看。花10分钟检查,能省下后面调模型的好几天时间。