4、情感词典构建:通用情感词典与金融领域定制

情感词典这东西,说白了就是一张「词-情绪」的映射表。你给模型一个词,它告诉你这是正面还是负面。听起来简单,但实际做起来坑不少。我刚开始做情感分析时,直接拿通用词典往金融文本上套,结果惨不忍睹——「负债」在通用词典里是中性词,但在财报里明显是负面信号。嗯,这就是我们今天要聊的核心问题。

4.1 通用情感词典:Loughran-McDonald 词典

先说说最经典的通用词典。Loughran-McDonald(简称LM词典)是金融领域绕不开的基准。它基于10-K年报语料构建,专门针对金融文本做了优化。

LM词典的核心特点:

  • 六大类别:正面、负面、不确定性、诉讼、强语气、弱语气
  • 词量:约8.5万个词条,其中负面词约2,300个
  • 去歧义处理:比如「liability」在通用词典里是中性,LM标注为负面

我个人习惯用LM词典做基线。为什么?因为它公开、稳定、被引用了上千次。你想想看,如果你要发论文或者做策略回测,用LM词典至少不会被审稿人质疑「你的词典哪来的」。

关键洞察:LM词典的负面词比正面词更有效。我在项目中测试过,负面词占比与股票收益率的相关性(-0.12)远高于正面词(0.03)。说白了,市场对坏消息更敏感。

下面是我常用的加载方式:

import pandas as pd

# 加载LM词典(假设已下载CSV格式)
lm_dict = pd.read_csv('LoughranMcDonald_MasterDictionary.csv')
negative_words = set(lm_dict[lm_dict['Negative'] > 0]['Word'].str.lower())
positive_words = set(lm_dict[lm_dict['Positive'] > 0]['Word'].str.lower())

# 快速测试
sample_text = "The company reported a loss due to litigation costs."
words = sample_text.lower().split()
neg_count = sum(1 for w in words if w in negative_words)
pos_count = sum(1 for w in words if w in positive_words)
print(f"负面词数: {neg_count}, 正面词数: {pos_count}")

4.2 金融领域情感词典定制

通用词典有个硬伤——它不懂金融黑话。比如「write-down」(资产减记)、「restructuring」(重组),这些词在通用词典里可能是中性,但在金融语境下明显偏负面。

定制词典的三种思路:

  1. 基于种子词扩展:先找50-100个金融情感种子词,然后用Word2Vec找相似词
  2. 基于语料统计:用大量金融文本,计算每个词在正面/负面文档中的TF-IDF差异
  3. 半自动标注:用少量人工标注+主动学习迭代

我推荐第二种方法,效率最高。具体怎么做?

from sklearn.feature_extraction.text import TfidfVectorizer
import numpy as np

# 假设我们有标注好的金融文本(正面/负面)
positive_docs = [...]  # 正面财报、新闻
negative_docs = [...]  # 负面财报、新闻

# 分别计算TF-IDF
vec = TfidfVectorizer(max_features=5000, stop_words='english')
pos_matrix = vec.fit_transform(positive_docs)
neg_matrix = vec.transform(negative_docs)

# 计算每个词在正/负语料中的平均TF-IDF差异
pos_avg = np.array(pos_matrix.mean(axis=0)).flatten()
neg_avg = np.array(neg_matrix.mean(axis=0)).flatten()
diff = pos_avg - neg_avg

# 提取情感词
feature_names = vec.get_feature_names_out()
custom_dict = {}
for i, word in enumerate(feature_names):
    if diff[i] > 0.1:  # 正面倾向
        custom_dict[word] = 'positive'
    elif diff[i] < -0.1:  # 负面倾向
        custom_dict[word] = 'negative'

避坑指南:我曾经直接用全量语料跑TF-IDF,结果「the」「and」这种词也进了词典。记得一定要先去掉停用词,并且设置合理的阈值。我一般用0.05作为门槛,低于这个值的词直接扔掉。

4.3 词典覆盖度评估

词典建好了,怎么知道它好不好用?三个指标:覆盖度准确率区分度

覆盖度评估:

  • 词级覆盖:词典能覆盖语料中多少比例的情感词
  • 文档级覆盖:多少文档至少有一个情感词被命中
  • 情感密度:每千词中情感词的数量

我一般用这个函数快速评估:

def evaluate_coverage(texts, sentiment_dict):
    total_words = 0
    matched_words = 0
    doc_covered = 0
    
    for text in texts:
        words = text.lower().split()
        total_words += len(words)
        matched = sum(1 for w in words if w in sentiment_dict)
        matched_words += matched
        if matched > 0:
            doc_covered += 1
    
    coverage = matched_words / total_words if total_words > 0 else 0
    doc_coverage = doc_covered / len(texts) if texts else 0
    
    return {
        'word_coverage': coverage,
        'doc_coverage': doc_coverage,
        'avg_density': matched_words / len(texts) if texts else 0
    }

下面这张图展示了词典构建的核心流程:

情感词典构建流程 通用情感词典 LM词典 / 通用词典 金融领域定制 种子词扩展 / TF-IDF统计 覆盖度评估 词级/文档级/密度 迭代优化:根据覆盖度结果补充词典 评估指标示例 指标 LM词典 定制词典 词级覆盖度 3.2% 7.8% 文档级覆盖度 68% 89%

注意:覆盖度不是越高越好。我曾经见过有人把词典扩到10万词,覆盖度到了15%,但准确率掉到了40%。为什么?因为很多词在不同语境下情感极性会反转。比如「volatility」在期权交易里是中性,但在散户新闻里是负面。所以评估时一定要同时看准确率。

准确率评估方法:

  • 随机抽取200-500条文本,人工标注情感
  • 用词典预测,计算精确率、召回率、F1
  • 重点关注负面词的召回率——金融策略里漏掉坏消息比误报好消息更致命

最后说一句,词典构建是个迭代活。我一般先跑LM词典做基线,然后针对特定领域(比如财报、新闻、社交媒体)分别定制子词典。每个子词典单独评估覆盖度,最后合并成一个综合词典。这样既能保证通用性,又能提升领域精度。


公众号:蓝海资料掘金营,微信deep3321