3. 文本预处理
在金融文本相似度与公告去重任务中,原始文本往往来自不同渠道:交易所公告、PDF 抽取文本、新闻转载、研报摘要、Wind/同花顺导出数据。它们表面上都在描述同一件事,但字符层面差异极大。如果直接计算相似度,模型会把“2024年半年度报告”和“2024年半年度报告”判为不同文本,把“華泰證券”和“华泰证券”判为不同实体,把“净利润 1,234.56 万元”和“净利润1234.56万元”判为不同表述。因此,文本预处理不是可选项,而是决定去重召回率与准确率的第一道工程关口。
一、核心原理:把“表面不同、语义相同”的文本拉齐到同一表示空间
预处理的本质是归一化与结构化。归一化解决字符层面的等价问题,结构化解决语义单元的切分问题。金融文本有三个显著特点:一是数字、日期、金额、百分比密集;二是实体名称存在繁简、全半角、简称与全称混用;三是公告模板化程度高,但转载平台会插入页眉页脚、免责声明、空格与换行。预处理的目标不是“清洗得越干净越好”,而是在保留判别性信息的前提下,消除与语义无关的噪声。
需要特别注意的是,金融文本中的数字和日期往往本身就是关键特征。例如“2023年年度报告”与“2024年年度报告”仅差一个数字,若在标准化时把年份直接删除,就会导致严重误判。因此数字与日期标准化的原则是统一格式而非丢弃内容。
二、方法流程:五步预处理的标准动作
下面给出一条可直接落地的处理链,顺序很重要:先做字符级归一化,再做词级处理,最后做结构化标注。
- 繁简转换:统一转为简体。金融文本中港台来源的公告、老研报常含繁体,如“證券”“營收”“淨利”。可使用 OpenCC 的
t2s配置。 - 全半角归一化:将全角字母、数字、标点转为半角,同时统一中文标点。注意全角空格
\u3000要转为普通空格或删除。 - 数字与日期标准化:把“二〇二四年六月三十日”“2024/6/30”“2024.06.30”统一为
2024-06-30;把“1,234.56万元”“1234.56萬”统一为1234.56万元。 - 中文分词:使用 jieba 或 LTP,并加载金融自定义词典,确保“宁德时代”“扣非净利润”“可转债”等不被切碎。
- 去停用词:在通用停用词表基础上,加入公告高频但无判别力的词,如“本公司”“董事会”“敬请”“投资者注意”。
推荐处理顺序:繁简转换 → 全半角归一化 → 数字日期标准化 → 分词 → 去停用词。若先分词再归一化,全角字符会导致分词错误;若先去停用词再标准化,可能误删包含数字的关键词。
三、案例与场景:一段公告文本的完整变形
假设原始文本来自某港交所公告的 PDF 抽取结果:
【原文】
華泰證券股份有限公司(「本公司」)謹此公佈,截至2024年6月30日止六個月,
本集團實現營業收入人民幣123.45億元,較去年同期增長8.76%。
【繁简转换后】
华泰证券股份有限公司(「本公司」)谨此公布,截至2024年6月30日止六个月,
本集团实现营业收入人民币123.45亿元,较去年同期增长8.76%。
【全半角归一化后】
华泰证券股份有限公司(「本公司」)谨此公布,截至2024年6月30日止六个月,
本集团实现营业收入人民币123.45亿元,较去年同期增长8.76%。
【数字日期标准化后】
华泰证券股份有限公司(「本公司」)谨此公布,截至2024-06-30止六个月,
本集团实现营业收入人民币123.45亿元,较去年同期增长8.76%。
【分词+去停用词后】
华泰证券 股份有限公司 公布 2024-06-30 止 六个月 本集团 实现 营业收入 人民币 123.45 亿元 较 去年同期 增长 8.76%
可以看到,经过五步处理后,文本从“不可比”变为“可比”。此时再计算余弦相似度或 Jaccard 相似度,才能真实反映两篇公告是否在讲同一件事。
| 处理步骤 | 典型输入 | 标准化输出 | 金融场景价值 |
|---|---|---|---|
| 繁简转换 | 華泰證券、淨利潤 | 华泰证券、净利润 | 统一港台与内地文本 |
| 全半角归一化 | ABC、123、() | ABC、123、() | 消除排版差异 |
| 数字标准化 | 1,234.56、1234.56 | 1234.56 | 金额可比 |
| 日期标准化 | 2024/6/30、二〇二四年六月三十日 | 2024-06-30 | 报告期对齐 |
| 分词 | 宁德时代、扣非净利润 | 宁德时代 / 扣非净利润 | 实体与科目完整 |
| 去停用词 | 本公司、敬请、注意 | 删除 | 降低模板噪声 |
四、误区与复盘:预处理中最容易踩的坑
误区一:停用词表一刀切。通用停用词表包含“不”“无”“未”等否定词,但在金融文本中,“未”“不”直接决定语义方向,如“未发生重大变化”与“发生重大变化”含义相反。否定词必须保留。
误区二:数字全部替换为占位符。有些教程建议把数字统一替换为 <NUM>,这在通用文本分类中可行,但在公告去重中会抹掉“2023”与“2024”的关键差异,导致年度报告被误判为重复。
误区三:分词词典不更新。金融领域新词、证券简称、并购事件名称层出不穷。若词典长期不更新,“寒武纪”“英伟达产业链”等会被切碎,直接影响相似度计算。
复盘建议:建立预处理回归测试集,选取 50~100 对已知“应判重”和“不应判重”的公告文本,每次调整停用词表或分词词典后,重新跑一遍召回率与准确率,确保预处理改动不会引入新的误判。
最后给出一个可复用的 Python 预处理函数骨架,便于在工程中直接接入:
import re
import jieba
from opencc import OpenCC
cc = OpenCC('t2s')
jieba.load_userdict('finance_dict.txt')
STOPWORDS = set(open('finance_stopwords.txt', encoding='utf-8').read().split())
def normalize(text: str) -> str:
text = cc.convert(text) # 繁简转换
text = text.replace('\u3000', ' ') # 全角空格
text = re.sub(r'[A-Za-z0-9]',
lambda m: chr(ord(m.group()) - 0xFEE0), text) # 全半角
text = re.sub(r'(\d{4})[年/.](\d{1,2})[月/.](\d{1,2})日?',
lambda m: f"{m.group(1)}-{int(m.group(2)):02d}-{int(m.group(3)):02d}",
text) # 日期标准化
text = re.sub(r'(?<=\d),(?=\d{3})', '', text) # 千分位
return text
def tokenize(text: str):
text = normalize(text)
tokens = [t for t in jieba.lcut(text) if t.strip() and t not in STOPWORDS]
return tokens
掌握这五步预处理,后续的向量化、相似度计算与去重策略才有可靠的基础。预处理的质量,直接决定了整个金融文本去重系统的上限。