文本预处理:让机器读懂金融文本的必修课

文本预处理,说白了就是给原始文本「洗澡」。金融文本里充斥着各种噪音——乱码、特殊符号、无意义的语气词,还有那些让分词器头疼的专有名词。我刚开始做金融NLP时,觉得这步可有可无,直到模型在「科创板」和「创业板」上频频翻车……嗯,从那以后我再也不敢跳过预处理了。

核心要点:文本预处理的质量,直接决定了RAG系统的检索精度。你喂给模型什么,它就消化什么。垃圾进,垃圾出。

1. 文本清洗:先去掉那些没用的东西

金融文本来源五花八门——研报、公告、新闻、论坛帖子。每个来源都有自己的「脏数据」特点。我个人习惯先做这几步:

  • 去除HTML标签:爬虫拿到的文本经常夹带<div>、<p>之类的标签
  • 统一全角半角:中文全角逗号和英文半角逗号混在一起,分词器会懵
  • 过滤特殊字符:比如「◆」「★」这些装饰符号,对语义理解没帮助
  • 去除多余空白:连续的空格、换行符,压缩成一个空格就行

我的经验:清洗规则别写太死。我在项目中遇到过一份财报,里面用「◆」标记重要数据,直接删掉反而丢了关键信息。建议先做数据探索,再定清洗策略。

import re

def clean_text(text):
    # 去除HTML标签
    text = re.sub(r'<[^>]+>', '', text)
    # 统一全角半角
    text = text.replace(',', ',').replace('。', '.').replace(';', ';')
    # 过滤特殊字符(保留中文、英文、数字、常见标点)
    text = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9\s,.;:!?()()【】《》]', '', text)
    # 压缩多余空白
    text = re.sub(r'\s+', ' ', text).strip()
    return text

2. 中文分词:jieba 的正确打开方式

中文不像英文天然有空格分隔。分词是第一步,也是最容易出问题的一步。jieba 是主流工具,但默认词典对金融领域不太友好。

为什么会这样?因为「做多」「量化宽松」「逆回购」这些词,jieba 默认会切成单字或错误组合。你想想看,「逆回购」被切成「逆」「回购」,检索时根本匹配不到正确的金融实体。

2.1 加载自定义词典

我建议把金融专有名词整理成一个词典文件,每行一个词,格式如下:

量化宽松 5 n
逆回购 5 n
科创板 5 n
注册制 5 n
北向资金 5 n

加载方式很简单:

import jieba

# 加载自定义词典
jieba.load_userdict('finance_dict.txt')

text = "央行开展逆回购操作,北向资金持续流入科创板"
words = jieba.lcut(text)
print(words)
# 输出:['央行', '开展', '逆回购', '操作', ',', '北向资金', '持续', '流入', '科创板']

注意:词典文件编码必须是 UTF-8,否则 jieba 会报错。我曾经因为这个坑排查了半天……

2.2 调整分词模式

jieba 有三种模式:精确模式、全模式、搜索引擎模式。对于 RAG 系统,我推荐用精确模式。全模式虽然召回率高,但会产生大量冗余词,增加向量存储的压力。

# 精确模式(推荐)
words = jieba.lcut(text, cut_all=False)

# 搜索引擎模式(适合长文本检索)
words = jieba.lcut_for_search(text)

3. 停用词过滤:去掉那些「废话」

停用词就是「的」「了」「在」「是」这类高频但无实际意义的词。金融文本里还有一些特殊的停用词,比如「本公司」「上述」「如下」——这些词在检索时只会增加噪音。

我一般准备两份停用词表:

  • 通用停用词表:覆盖常见的中文停用词
  • 金融专用停用词表:针对财报、公告中的套话
def remove_stopwords(words, stopwords_set):
    return [w for w in words if w not in stopwords_set and len(w) > 1]

# 加载停用词表
with open('stopwords.txt', 'r', encoding='utf-8') as f:
    stopwords = set([line.strip() for line in f])

filtered_words = remove_stopwords(words, stopwords)

避坑指南:我曾经把「不」加入停用词表,结果「不看好」「不达标」这类否定表达全被过滤了,模型完全理解反了意思。停用词表要谨慎,尤其是金融领域,否定词往往很关键。

4. 实体识别:金融专有名词的精准捕获

实体识别(NER)是文本预处理的高级阶段。金融领域有大量专有名词——公司名、产品名、指标名、政策名。这些实体如果识别不出来,检索时就会漏掉关键信息。

4.1 基于词典的匹配

最简单也最可靠的方法,就是用词典做最大正向匹配。我习惯把金融实体分成几类:

实体类型 示例 来源
公司名称 贵州茅台、宁德时代、中国平安 上市公司列表
金融产品 沪深300ETF、中证500指数 交易所产品目录
经济指标 CPI、PMI、LPR、GDP 统计局/央行发布
政策术语 注册制、科创板、北交所 监管文件
class FinanceNER:
    def __init__(self, entity_dict):
        self.entity_dict = entity_dict  # {实体: 类型}
        self.max_len = max(len(e) for e in entity_dict)
    
    def extract(self, text):
        entities = []
        i = 0
        while i < len(text):
            matched = False
            for j in range(self.max_len, 0, -1):
                if i + j <= len(text):
                    word = text[i:i+j]
                    if word in self.entity_dict:
                        entities.append((word, self.entity_dict[word], i, i+j))
                        i += j
                        matched = True
                        break
            if not matched:
                i += 1
        return entities

4.2 结合分词结果

更聪明的做法是把实体识别和分词结合起来。先用自定义词典让 jieba 正确切分专有名词,再通过词性标注提取实体。

import jieba.posseg as pseg

def extract_finance_entities(text):
    words = pseg.lcut(text)
    entities = []
    for word, flag in words:
        # 自定义词典中标记为 n 的金融名词
        if flag == 'n' and word in finance_dict:
            entities.append(word)
    return entities

5. 完整预处理流程

把上面几步串起来,就是一个完整的预处理管线。我画了一张流程图,帮你理清逻辑:

金融文本预处理流程 原始文本 文本清洗 中文分词(jieba) 停用词过滤 实体识别(NER) 去除HTML、特殊字符 加载自定义金融词典 过滤无意义高频词 提取公司、产品、指标

嗯,流程看起来不复杂,但每一步都有坑。我建议你在实际项目中,先拿一小批数据跑通流程,再逐步优化。别一上来就追求完美,迭代才是王道。

最终产出:经过预处理后的文本,应该是干净、结构化、实体清晰的。这样的文本送入向量模型,才能生成高质量的嵌入向量,支撑后续的精准检索。


专注资料整理