文本预处理基础:中文分词、去停用词、词性标注与NER
各位同学好,我是老周。今天咱们聊聊金融文本预处理这块硬骨头。
说实话,很多做金融NLP的朋友,一上来就急着上模型。我见过太多人,数据还没洗干净,就跑去调BERT参数。结果呢?模型跑出来一堆噪音。文本预处理,说白了就是给模型喂饭前先洗菜切菜。菜不干净,再好的厨子也白搭。
这一章,我带你过一遍金融场景下最常用的四个预处理步骤:中文分词、去停用词、词性标注、命名实体识别。每个环节我都会结合自己踩过的坑来讲。
一、中文分词:Jieba 在金融场景的实战
中文分词,就是把一句话切成有意义的词。英文天然有空格分隔,中文没有。所以这是第一步。
Jieba 是目前最常用的分词工具。它支持三种模式:精确模式、全模式、搜索引擎模式。我个人习惯用精确模式做金融分析,因为它切得准,不会把「中国人民银行」切成「中国/人民/银行」这种低级错误。
import jieba
# 加载金融自定义词典
jieba.load_userdict('finance_dict.txt')
text = "央行今日开展逆回购操作,释放流动性5000亿元"
words = jieba.lcut(text)
print(words)
# 输出:['央行', '今日', '开展', '逆回购', '操作', ',', '释放', '流动性', '5000亿元']
你看,「逆回购」被正确识别为一个词。如果不加自定义词典,Jieba 可能会切成「逆/回购」。这在情感分析里会出大问题——「逆」和「回购」单独看,情感极性完全不同。
二、去停用词:别让噪音干扰模型
停用词就是那些高频但没啥实际意义的词,比如「的」「了」「在」「是」。在金融文本里,还有一类特殊的停用词:数字单位、标点符号、无意义的动词。
举个例子:「公司本年度实现净利润较上年同期增长12.5%。」去掉停用词后变成:「公司 本年度 实现 净利润 较 上年 同期 增长 12.5%」。嗯,这里「较」「同期」其实是有意义的,不能一刀切。
# 金融场景停用词处理示例
stop_words = set(['的', '了', '在', '是', '有', '和', '与', '及'])
# 注意:不要包含否定词、程度副词
negation_words = ['不', '没有', '并非', '尚未']
def filter_stopwords(words, stop_words, negation_words):
result = []
for w in words:
if w in stop_words:
continue
result.append(w)
return result
三、词性标注:给每个词打上标签
词性标注,就是给每个词标上它是名词、动词、形容词还是其他。为什么需要这个?因为金融文本里,同一个词在不同语境下词性不同,情感也不同。
比如「风险」这个词,在「控制风险」里是名词,在「风险投资」里是形容词。Jieba 的词性标注功能可以帮我们区分。
| 词 | 词性 | 金融场景示例 |
|---|---|---|
| 增长 | v (动词) | 「净利润增长20%」 |
| 增长 | n (名词) | 「实现正增长」 |
| 风险 | n (名词) | 「信用风险暴露」 |
| 风险 | vn (名动词) | 「风险控制体系」 |
import jieba.posseg as pseg
text = "该基金主要投资于高收益债券"
words = pseg.lcut(text)
for word, flag in words:
print(f'{word} -> {flag}')
# 输出:
# 该 -> r
# 基金 -> n
# 主要 -> b
# 投资 -> vn
# 于 -> p
# 高收益 -> n
# 债券 -> n
你看,「投资」被标为 vn(名动词),「高收益」被标为 n(名词)。这些信息在后续情感打分时非常有用——我们通常只对形容词和动词做情感计算,名词一般不做。
四、命名实体识别(NER):找到关键信息
NER 是文本预处理里最有意思的一步。它的目标是找出文本中的专有名词:公司名、人名、地名、日期、金额、股票代码等。
在金融领域,NER 的准确率直接影响下游任务。比如「阿里巴巴集团控股有限公司发布2023年财报」,如果 NER 没识别出「阿里巴巴集团控股有限公司」是一个完整的实体,后面做舆情分析时就会漏掉这家公司。
- ORG - 机构名:工商银行、中国平安、高盛
- PER - 人名:易纲、刘鹤、巴菲特
- DATE - 日期:2023年12月31日、Q3
- MONEY - 金额:5000亿元、1.2亿美元
- STOCK - 股票代码:600519、000001
我一般用两种方式做金融 NER:一是基于规则(正则匹配股票代码、金额),二是基于模型(BERT-CRF 微调)。对于刚起步的项目,我建议先用规则兜底,再上模型。
# 简单的金融 NER 规则示例
import re
def extract_finance_entities(text):
entities = []
# 匹配金额:数字+亿元/万美元
money_pattern = r'\d+\.?\d*[万亿]?[元美元]'
for match in re.finditer(money_pattern, text):
entities.append(('MONEY', match.group(), match.start(), match.end()))
# 匹配股票代码:6位数字
stock_pattern = r'\b[0-9]{6}\b'
for match in re.finditer(stock_pattern, text):
entities.append(('STOCK', match.group(), match.start(), match.end()))
return entities
text = "贵州茅台(600519)2023年营收突破1500亿元"
print(extract_finance_entities(text))
# 输出:[('STOCK', '600519', 5, 11), ('MONEY', '1500亿元', 18, 25)]
五、四个步骤的串联实战
好了,四个步骤都讲完了。在实际项目中,它们不是孤立的。我通常按这个流程走:
- 原始文本 → 清洗(去HTML标签、全角转半角)
- Jieba 分词 + 加载金融自定义词典
- 去停用词(保留否定词和程度副词)
- 词性标注(只保留形容词、动词、名词)
- NER 抽取(识别公司、金额、日期等关键实体)
这一套下来,文本就从「央行今日开展逆回购操作,释放流动性5000亿元」变成了结构化的数据:动作=逆回购,金额=5000亿元,主体=央行,情感=正面。
嗯,预处理做到这个程度,后面的情感建模就轻松多了。你想想看,如果连「逆回购」和「逆/回购」都分不清,模型怎么可能学对?
下一章我会讲情感词典的构建,那是另一个有意思的话题。今天就到这儿。
公众号:蓝海资料掘金营,微信deep3321