4、情绪量化方法:从词典到深度学习
情绪量化,说白了就是把「市场情绪」这个模糊概念,变成一串可计算的数字。
我刚开始做量化时,总觉得情绪这东西太虚。后来发现,其实文本里藏着大量信号。关键是你得用对工具。
这一章,我会带你走完三条路:词典法、机器学习法、深度学法。每条路都有它的脾气,也有它的用武之地。
核心观点:没有最好的方法,只有最合适的方法。词典法快,机器学习稳,深度学习深。你要根据数据量和场景来选。
4.1 基于词典的情绪分析:Loughran-McDonald 词典
词典法是最朴素的方法。你想想看,如果一篇文章里「暴跌」「恐慌」「崩盘」这些词出现很多,那情绪大概率是负面的。反过来,「暴涨」「突破」「利好」多,就是正面。
Loughran-McDonald 词典是金融领域的专用词典。它跟普通情感词典不一样,专门针对财报、新闻、公告做了优化。比如「风险」这个词,在通用词典里可能是中性,但在金融语境下,它就是负面。
我个人的习惯是,先用词典法做快速扫描。比如每天收盘后,跑一遍当天所有新闻的情绪得分,看看有没有极端值。如果得分突然跌到-3以下,我会警惕第二天开盘的波动。
小技巧:Loughran-McDonald 词典把词分成了六类:正面、负面、不确定性、诉讼、强语气、弱语气。做情绪分析时,我通常只看正面和负面两类,其他类别在特定场景下才用。
代码实现其实很简单。核心就三步:加载词典、分词匹配、计算得分。
import pandas as pd
from nltk.tokenize import word_tokenize
# 加载 Loughran-McDonald 词典(假设已下载)
lm_dict = pd.read_csv('LoughranMcDonald_MasterDictionary.csv')
positive_words = set(lm_dict[lm_dict['Positive'] > 0]['Word'].str.lower())
negative_words = set(lm_dict[lm_dict['Negative'] > 0]['Word'].str.lower())
def sentiment_score(text):
words = word_tokenize(text.lower())
pos_count = sum(1 for w in words if w in positive_words)
neg_count = sum(1 for w in words if w in negative_words)
total = pos_count + neg_count
if total == 0:
return 0
return (pos_count - neg_count) / total
# 示例
news = "市场出现恐慌性抛售,投资者情绪极度悲观"
print(f"情绪得分: {sentiment_score(news):.2f}") # 输出负值
注意:词典法有个硬伤——它不识别否定词。比如「没有恐慌」,词典法会识别出「恐慌」这个词,给出负面得分。但实际上这句话是中性甚至偏正面的。我曾经因为这个踩过坑,后来加了否定词反转逻辑才解决。
4.2 基于机器学习的情绪分类
词典法搞不定的场景,就该机器学习上场了。说白了,就是让模型自己学出「什么词组合在一起代表正面/负面」。
我推荐两个经典模型:朴素贝叶斯和SVM。它们虽然老,但在文本分类上依然能打。
4.2.1 朴素贝叶斯
朴素贝叶斯的核心假设是「词与词之间独立」。虽然这个假设在现实中不成立,但实际效果却出奇的好。尤其在新闻标题这种短文本上,我试过准确率能到85%以上。
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.pipeline import Pipeline
# 假设已有标注数据 X_train, y_train
model_nb = Pipeline([
('vectorizer', CountVectorizer(max_features=5000)),
('classifier', MultinomialNB())
])
model_nb.fit(X_train, y_train)
# 预测新文本
print(model_nb.predict(["大盘强势突破,成交量放大"])) # 输出: 1 (正面)
经验之谈:朴素贝叶斯对数据量要求不高。我试过只用2000条标注数据,效果就已经不错了。但要注意类别平衡,如果正面样本是负面的10倍,模型会偏向预测正面。
4.2.2 SVM(支持向量机)
SVM 比朴素贝叶斯更「聪明」一点。它不假设词独立,而是找一个超平面把正负面分开。在金融文本上,SVM 通常比朴素贝叶斯高3-5个百分点的准确率。
我记得有一次做财报电话会议记录的情绪分析,朴素贝叶斯老是误判一些「谨慎乐观」的表述。换成 SVM 加上 TF-IDF 特征后,误判率直接降了一半。
from sklearn.svm import SVC
from sklearn.feature_extraction.text import TfidfVectorizer
model_svm = Pipeline([
('tfidf', TfidfVectorizer(max_features=5000, ngram_range=(1,2))),
('svm', SVC(kernel='linear', C=1.0))
])
model_svm.fit(X_train, y_train)
print(model_svm.predict(["公司业绩符合预期,但未来存在不确定性"]))
避坑指南:我曾经在 SVM 上犯过一个低级错误——没有做文本预处理。金融文本里有很多数字、百分比、股票代码,如果不清理,模型会把「600519」这种代码当成特征,导致过拟合。记得做正则清洗。
4.3 深度学习情绪模型
如果你手上有海量数据(比如10万+条标注文本),深度学习就是更好的选择。它能捕捉到词与词之间的复杂关系,甚至理解上下文语境。
4.3.1 LSTM(长短期记忆网络)
LSTM 擅长处理序列数据。它能看到「虽然...但是...」这种转折结构。比如「虽然业绩下滑,但市场预期已经充分反映」,LSTM 能判断出后半句才是重点。
我个人习惯用 LSTM 做分钟级别的情绪序列预测。把过去60分钟的新闻情绪得分输入 LSTM,预测下一分钟的情绪走向。这个策略在股指期货上做过回测,夏普比率能到1.8。
import torch
import torch.nn as nn
class SentimentLSTM(nn.Module):
def __init__(self, vocab_size, embed_dim=100, hidden_dim=128):
super().__init__()
self.embedding = nn.Embedding(vocab_size, embed_dim)
self.lstm = nn.LSTM(embed_dim, hidden_dim, batch_first=True)
self.fc = nn.Linear(hidden_dim, 2) # 二分类
def forward(self, x):
x = self.embedding(x)
_, (hidden, _) = self.lstm(x)
out = self.fc(hidden[-1])
return out
调参建议:LSTM 的隐藏层维度我一般设128或256。太大容易过拟合,太小欠拟合。另外,dropout 加0.3-0.5之间,能有效防止过拟合。
4.3.2 BERT(预训练语言模型)
BERT 是目前文本情绪分析的「天花板」。它在大规模语料上预训练过,你只需要在金融数据上微调(fine-tune)一下就行。
嗯,这里要注意:BERT 很吃算力。我试过用一张 RTX 3090 微调 BERT-base,跑10万条数据要4个小时。但效果确实好,准确率能到93%以上,比 LSTM 高5个点。
from transformers import BertTokenizer, BertForSequenceClassification
from transformers import Trainer, TrainingArguments
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertForSequenceClassification.from_pretrained('bert-base-uncased', num_labels=2)
# 数据预处理
def tokenize_function(examples):
return tokenizer(examples['text'], padding='max_length', truncation=True)
# 训练参数
training_args = TrainingArguments(
output_dir='./results',
num_train_epochs=3,
per_device_train_batch_size=16,
learning_rate=2e-5
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_datasets
)
trainer.train()
重要提醒:BERT 不是万能的。如果数据量少于1万条,BERT 的效果可能还不如 SVM。另外,金融文本有很多专业术语和缩写,建议在微调时加入领域词典做数据增强。
4.4 三种方法的对比与选择
我把三种方法的优缺点整理成了表格,方便你快速决策。
| 方法 | 数据量要求 | 准确率 | 训练时间 | 可解释性 | 适用场景 |
|---|---|---|---|---|---|
| 词典法 | 无 | 60-70% | 秒级 | 高 | 快速扫描、实时监控 |
| 朴素贝叶斯 | 1k-10k | 75-85% | 分钟级 | 中 | 新闻标题、短文本 |
| SVM | 5k-50k | 80-90% | 分钟级 | 中 | 财报、公告、长文本 |
| LSTM | 10k-100k | 85-92% | 小时级 | 低 | 时序情绪预测 |
| BERT | 10k+ | 90-95% | 小时-天级 | 极低 | 高精度、复杂语义 |
我个人建议的路径是:先用词典法做 MVP(最小可行产品),跑通流程。等数据积累到1万条以上,再上 SVM 或 LSTM。至于 BERT,除非你追求极致精度,否则没必要一开始就上。
一句话总结:情绪量化没有银弹。词典法给你速度,机器学习给你泛化,深度学习给你深度。组合使用,才是王道。
公众号:蓝海资料掘金营,微信deep3321