3. 文本预处理

在金融文本相似度与公告去重任务中,原始文本往往来自不同渠道:交易所公告、PDF 抽取文本、新闻转载、研报摘要、Wind/同花顺导出数据。它们表面上都在描述同一件事,但字符层面差异极大。如果直接计算相似度,模型会把“2024年半年度报告”和“2024年半年度报告”判为不同文本,把“華泰證券”和“华泰证券”判为不同实体,把“净利润 1,234.56 万元”和“净利润1234.56万元”判为不同表述。因此,文本预处理不是可选项,而是决定去重召回率与准确率的第一道工程关口。

一、核心原理:把“表面不同、语义相同”的文本拉齐到同一表示空间

预处理的本质是归一化与结构化。归一化解决字符层面的等价问题,结构化解决语义单元的切分问题。金融文本有三个显著特点:一是数字、日期、金额、百分比密集;二是实体名称存在繁简、全半角、简称与全称混用;三是公告模板化程度高,但转载平台会插入页眉页脚、免责声明、空格与换行。预处理的目标不是“清洗得越干净越好”,而是在保留判别性信息的前提下,消除与语义无关的噪声。

需要特别注意的是,金融文本中的数字和日期往往本身就是关键特征。例如“2023年年度报告”与“2024年年度报告”仅差一个数字,若在标准化时把年份直接删除,就会导致严重误判。因此数字与日期标准化的原则是统一格式而非丢弃内容。

金融文本预处理流水线 原始文本 PDF/公告/新闻 繁简转换 華泰→华泰 全半角归一 ABC→ABC 数字日期标准化 2024-06-30 中文分词 jieba/LTP 去停用词 的/了/及/本公司 金融词典增强 自定义实体词 标准化序列 供相似度计算 关键原则: ① 数字与日期只统一格式,不删除内容;② 停用词表需按金融场景定制;③ 分词词典必须包含公司名、证券简称、财务科目。

二、方法流程:五步预处理的标准动作

下面给出一条可直接落地的处理链,顺序很重要:先做字符级归一化,再做词级处理,最后做结构化标注。

  1. 繁简转换:统一转为简体。金融文本中港台来源的公告、老研报常含繁体,如“證券”“營收”“淨利”。可使用 OpenCC 的 t2s 配置。
  2. 全半角归一化:将全角字母、数字、标点转为半角,同时统一中文标点。注意全角空格 \u3000 要转为普通空格或删除。
  3. 数字与日期标准化:把“二〇二四年六月三十日”“2024/6/30”“2024.06.30”统一为 2024-06-30;把“1,234.56万元”“1234.56萬”统一为 1234.56万元。
  4. 中文分词:使用 jieba 或 LTP,并加载金融自定义词典,确保“宁德时代”“扣非净利润”“可转债”等不被切碎。
  5. 去停用词:在通用停用词表基础上,加入公告高频但无判别力的词,如“本公司”“董事会”“敬请”“投资者注意”。

推荐处理顺序:繁简转换 → 全半角归一化 → 数字日期标准化 → 分词 → 去停用词。若先分词再归一化,全角字符会导致分词错误;若先去停用词再标准化,可能误删包含数字的关键词。

三、案例与场景:一段公告文本的完整变形

假设原始文本来自某港交所公告的 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

掌握这五步预处理,后续的向量化、相似度计算与去重策略才有可靠的基础。预处理的质量,直接决定了整个金融文本去重系统的上限。