3. 数据清洗与预处理:文本去噪、分词技术、停用词过滤、实体识别基础
好,咱们进入第三章。说实话,金融事件分析这个事儿,很多人一上来就急着上模型、跑算法。我见过不少团队,数据还没洗干净呢,就开始调参了。结果呢?模型跑出来的结果,连自己都不敢信。
数据清洗与预处理,说白了就是给原始文本“洗澡”。金融文本有多脏?我举个例子——你从交易所拿到的公告原文,里面可能夹杂着HTML标签、乱码字符、甚至还有OCR识别错的符号。这些垃圾不清理掉,后面的分词、实体识别全都会跑偏。
3.1 文本去噪:把垃圾扔出去
文本去噪,我的理解就是“保留有用的,扔掉没用的”。金融文本里常见的噪声包括:
- HTML/XML标签:比如
<div>、<p>这些 - 特殊符号:乱码、不可见字符、多余的标点
- URL链接:很多公告里会带网址,分析时基本没用
- 数字与单位混排:比如“1,234.56元”这种,需要规范化
我个人习惯用正则表达式做第一轮清洗。给你看一段我常用的代码:
import re
def clean_financial_text(text):
# 去掉HTML标签
text = re.sub(r'<[^>]+>', '', text)
# 去掉URL
text = re.sub(r'http[s]?://\S+', '', text)
# 保留中文、英文、数字、常用标点
text = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9,。!?、;:""''()【】]', '', text)
# 合并多余空格
text = re.sub(r'\s+', ' ', text).strip()
return text
3.2 分词技术:把句子切成词
中文分词,嗯,这是个老话题了。但金融领域的分词,跟新闻领域完全不是一回事。你想想看,“中国人民银行”这个词,如果被切成“中国”、“人民”、“银行”,那意思就全变了。
目前主流的分词工具,我比较推荐这几个:
| 工具 | 特点 | 金融场景适用性 |
|---|---|---|
| jieba | 轻量、速度快、支持自定义词典 | ★★★★☆ |
| HanLP | 功能全面、支持命名实体识别 | ★★★★★ |
| LAC (百度) | 词性标注准确率高 | ★★★★☆ |
| pkuseg | 北大出品,多领域模型 | ★★★☆☆ |
我个人在金融项目里用得最多的是 jieba + 自定义词典 的组合。为什么?因为金融术语太特殊了。比如“定向增发”、“股权质押”、“可转债”,这些词通用分词器很容易切错。
给你看个例子:
import jieba
# 加载金融自定义词典
jieba.load_userdict('finance_dict.txt')
text = "公司拟通过定向增发募集资金用于收购标的公司股权"
words = jieba.lcut(text)
print(words)
# 输出:['公司', '拟', '通过', '定向增发', '募集资金', '用于', '收购', '标的公司', '股权']
3.3 停用词过滤:去掉没营养的词
停用词,说白了就是那些出现频率高但没啥实际意义的词。比如“的”、“了”、“在”、“是”、“一个”等等。在金融文本里,还有一些特殊的停用词,比如“本公司”、“上述”、“如下”这类。
为什么要过滤?你想想看,如果“的”这个词在每篇文档里都出现几百次,它对区分不同事件有什么帮助?几乎没有。反而会稀释掉真正重要的关键词。
我常用的做法是:
- 用一份通用中文停用词表(网上有很多开源版本)
- 再补充一份金融领域停用词表
- 两份合并去重后使用
def load_stopwords():
stopwords = set()
with open('cn_stopwords.txt', 'r', encoding='utf-8') as f:
for line in f:
stopwords.add(line.strip())
with open('finance_stopwords.txt', 'r', encoding='utf-8') as f:
for line in f:
stopwords.add(line.strip())
return stopwords
stopwords = load_stopwords()
filtered_words = [w for w in words if w not in stopwords and len(w) > 1]
3.4 实体识别基础:找到关键信息
实体识别,英文叫NER(Named Entity Recognition)。在金融事件分析里,我们要找的实体通常包括:
- 公司名称:比如“贵州茅台”、“中国平安”
- 人名:比如“董事长”、“总经理”
- 金额:比如“10亿元”、“500万美元”
- 日期:比如“2024年3月15日”
- 金融产品:比如“可转债”、“ETF”
实体识别的方法,我把它分成三个阶段:
第一阶段:基于规则
用正则表达式匹配固定模式。比如金额可以用 \d+\.?\d*\s*[万亿]?元 来匹配。这个方法简单粗暴,适合快速验证。
第二阶段:基于词典
把已知的实体列表做成词典,直接匹配。比如上市公司名单、高管名单。我做过一个项目,光公司词典就整理了3000多家。
第三阶段:基于模型
用预训练模型(比如BERT)来做序列标注。这个方法准确率高,但需要标注数据。我一般在前两个阶段搞不定的时候才上模型。
给你看个简单的基于词典的实体识别:
def entity_recognition(text, entity_dict):
entities = []
for entity_name, entity_type in entity_dict.items():
if entity_name in text:
entities.append({
'text': entity_name,
'type': entity_type,
'start': text.index(entity_name),
'end': text.index(entity_name) + len(entity_name)
})
return entities
# 示例
entity_dict = {
'贵州茅台': '公司',
'中国平安': '公司',
'马明哲': '人物'
}
text = "贵州茅台发布公告,中国平安董事长马明哲出席会议"
result = entity_recognition(text, entity_dict)
print(result)
3.5 本章知识体系
下面这张图,是我梳理的本章核心逻辑。你可以把它当作一个处理流水线来看:
你看,整个流程是串行的。每一步的输出,就是下一步的输入。我建议你在实际项目中,每一步都做一次质量检查。比如分词之后,随机抽100条看看切得对不对。别等到最后才发现问题,那时候改起来成本就高了。
好了,这一章的内容就这些。数据清洗虽然看起来基础,但说实话,它决定了整个分析系统的上限。你想想看,输入都是垃圾,输出能是黄金吗?