资讯动态

股市评论情感分析毕设:从TF-IDF/LSTM到情感指数可视化

发布时间:2026/10/19 11:10:50 来源:尧图企业网站定制
简介面向计算机相关专业毕业生的股市评论情感分析完整项目包整合机器学习与深度学习两套建模方案可用于毕业设计、课程设计或期末大作业。项目经导师指导并评审98分包含数据处理、模型训练、情感指数构建与可视化呈现的完整流程适合希望从零上手情感分析实战的本科或研究生。资源共12个文件压缩包约24.72MB以Python脚本、CSV数据文件、TXT情感词典/说明文档、PNG图表和Markdown报告为主覆盖股市评论数据、正负情感词典、机器学习与深度学习模型脚本、情感指数计算及可视化模块目录结构清晰便于按模块阅读和复现。目前已有394人学习下载资源附有报告文档和运行说明能够帮助读者快速理解实现思路、直接运行代码并根据自身数据替换扩展是金融文本挖掘方向较为完整的高分参考项目。1. 股市评论情感分析毕设不只是“跑通模型”而是交付一条完整的分析链路如果你正在为毕业设计或课程设计选题发愁又恰好学过一点 Python、机器学习或深度学习股市评论情感分析是一个很容易“讲出深度”的方向。它的魅力在于数据是现成的中文文本模型有现成的库可以用评价标准可以不只看准确率还能和真实的股票指数走势做对照做出“情感指数与大盘走势偏离度”这类有说服力的可视化结果。但这恰恰也是容易翻车的地方——很多人把跑通一个情感分类模型当成了整个项目结果答辩时被问到“情感指数是怎么算出来的”“负面词典和模型预测结果怎么融合”“结果图如何解释”就卡住了。这篇方案围绕一份实际完成的毕业设计展开它不只是贴一段训练代码而是从数据采集、清洗、标注到 SQLite 存储、机器学习与深度学习两条建模路径再到情感指数计算与可视化验证的完整工程。适合正在做毕设、课设或期末大作业的同学直接拆解参考也适合想快速搭建一个文本情感分析 Demo 的开发者。2. 总体架构设计六类文件如何组成一条完整的数据流这套项目拿到手里先不要急着跑代码先看清它分了几个层次。解压后的 Stock_MarketSentiment_Analysis-master 目录里核心文件其实就六类数据文件sh000001.csv、positive.txt、negative.txt、stock_comments.zip、机器学习脚本model_ml.py、深度学习脚本model_dl.py、情感指数计算脚本compute_sent_idx.py、可视化脚本plot_sent_idx.py以及结果文件model_ml_scores.csv、BI_and_Market.png、BI.png。如果只是把它们看成“一堆代码”你很难向导师讲清楚设计思路但如果你把它映射成一条数据流水线整个项目的骨架就清晰了。2.1 整条流水线的四个阶段我的习惯是先画一张数据流向图再开始写代码。对于这个项目数据流是“原始数据 → 文本预处理与标注 → 模型训练与预测 → 情感指数计算与可视化验证”。第一个阶段是数据准备。stock_comments.zip 里是采集到的某段时间的股评原始文本positive.txt 和 negative.txt 是整理好的正向、负向情感词典sh000001.csv 是上证指数历史行情数据。这三类数据共同构成了项目的事实基础评论用于生成情感信号词典用于冷启动和规则兜底指数数据用于后续验证情感指数是否有参考价值。第二个阶段是模型构建。model_ml.py 走传统机器学习路线核心思路是把文本转成 TF-IDF 特征再喂给逻辑回归或朴素贝叶斯分类器model_dl.py 走深度学习的路线用 Word2Vec 训练词向量再送入 LSTM 网络做分类。两条路线都要产出“每条评论的情感极性预测”这是后续所有分析的前提。第三个阶段是情感指数计算。compute_sent_idx.py 读入模型预测结果再结合 positive.txt 和 negative.txt 的词典得分按时间窗口聚合成一个可以度量的情绪指数BI。这一步是这类项目的灵魂单纯输出“正面/负面”没有说服力必须把它变成一条随时间变化的曲线。第四个阶段是验证与展示。plot_sent_idx.py 生成 BI.png情感指数随时间的变化曲线和 BI_and_Market.png情感指数与上证指数的对比图。答辩时这两张图是核心材料它们直接回答“你算出的这个情感指数到底有没有意义”。2.2 为什么文本分类要采用“机器学习 深度学习”双路线很多毕设项目只做一条路线但这套资源把两条路线都放进来这不是简单的堆代码而是有明确的设计考量。机器学习路线TF-IDF LR的优势在于可解释性强特征维度直观训练时间短适合在答辩时现场演示调参深度学习路线Word2Vec LSTM的优势在于能够捕捉上下文语义比如“这只股票真是要起飞了”这种带反讽意味的句子词袋模型容易分错LSTM 却能通过词序学到更准确的表示。两条路线对比着做正好回应答辩时导师最喜欢问的一个问题“你为什么不直接用 BERT” 这时候你可以回答BERT 效果可能更好但它需要较大的显存和较长的训练时间而 TF-IDF LR 和 Word2Vec LSTM 的组合在这个数据规模下已经能达到可用效果并且能够在普通笔记本上复现这正是毕设项目在工程约束条件下的合理选型。2.3 SQLite 存储与中间结果的复用设计项目里虽然没有单独列出建库脚本但从数据流来看中间结果被很好地复用这是值得借鉴的设计。compute_sent_idx.py 会读取 model_ml.py 产出的 model_ml_scores.csv 文件这个 CSV 就是模型预测结果的落地载体——每一行是某条评论的编号、时间戳和预测的情感极性分数。之所以不用数据库而是用 CSV是因为这个项目的数据量级在几百兆以下CSV 的读写速度足够快而且方便你在 Excel 里直接打开检查结果。我一般会建议你的项目里增加一个 to_sqlite.py 的辅助脚本把清洗后的评论、预测结果、词典得分分别存入三张表这样后续如果要扩展成“按天聚合情绪”“按个股筛选评论”SQL 查询会比 pandas 反复读 CSV 更高效。但从交付角度来说现有设计已经足够完成一个高分毕设数据库只是加分项不是必需项。文本预处理和特征构建是这个项目的实测难点很多人第一次跑通模型后准确率只有 60% 出头问题几乎都出在预处理阶段。我在第三、四章会把两条建模路径的代码逻辑和参数设计拆开讲清楚你拿到后可以对照自己的数据直接改。3. 机器学习建模实战model_ml.py 中的 TF-IDF 与逻辑回归model_ml.py 是整个项目里最容易先跑通、也最容易拿到稳定分数的模块。它的整体思路是读取评论数据 → 中文分词 → 去除停用词 → TF-IDF 向量化 → 逻辑回归分类 → 输出预测分数到 model_ml_scores.csv。下面先给出核心代码框架。3.1 文本预处理与 TF-IDF 特征构建import jieba import pandas as pd from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report # 读取评论与标签 df pd.read_csv(stock_comments.csv) # 字段comment, label, date stopwords set() with open(stopwords.txt, r, encodingutf-8) as f: for line in f: stopwords.add(line.strip()) def cut_text(text): words jieba.lcut(text) return .join([w for w in words if w not in stopwords and len(w) 1]) df[cut_comment] df[comment].apply(cut_text) # TF-IDF 特征 vectorizer TfidfVectorizer(max_features5000, ngram_range(1, 2)) X vectorizer.fit_transform(df[cut_comment]) y df[label] # 1 表示正面0 表示负面 # 划分训练集与测试集 X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, random_state42)这段代码里有几个参数需要重点说明答辩时很可能被问到。max_features5000 表示只保留 TF-IDF 权重最高的 5000 个特征这是为了控制特征矩阵的稀疏度和训练时间如果语料规模不大5000 已经足够覆盖绝大多数有效词ngram_range(1, 2) 表示同时使用单个词和相邻两个词的组合作为特征这样像“不看好”这种三字短语会被拆成“不 看好”和“不看 看好”两个特征片段比单纯用单个词多了一些语义信息。len(w) 1 这个过滤条件是为了去掉“的”“了”“啊”等单字词这些词在情感分析里几乎不携带极性信息保留它们只会增大特征维度。3.2 逻辑回归模型的训练与阈值选择model LogisticRegression(C1.0, solverliblinear, max_iter200) model.fit(X_train, y_train) y_pred model.predict(X_test) y_proba model.predict_proba(X_test)[:, 1] # 属于正面的概率 print(classification_report(y_test, y_pred)) # 将预测概率输出到 CSV供后续情感指数计算使用 df[pred_score] y_proba df[[date, comment, pred_score]].to_csv(model_ml_scores.csv, indexFalse, encodingutf-8-sig)为什么选择逻辑回归而不是 SVM 或随机森林这是很多同学会犹豫的地方。逻辑回归本质上是一个线性分类器加上 sigmoid 输出它的训练速度快可解释性好而且 predict_proba 直接给出样本属于“正面”的概率——这个概率值恰好是后续 compute_sent_idx.py 计算情感指数的核心输入。如果是随机森林虽然准确率可能略高一些但它的概率输出不如逻辑回归平滑而且训练和调参成本高对毕设项目的性价比反而不高。C1.0 是正则化强度的倒数C 越小正则化越强如果训练数据量在几千条量级1.0 是一个不需要过多调整的默认值。3.3 分类结果的检视方法把 model_ml_scores.csv 在 Excel 里打开你会看到每一条评论对应一个 0 到 1 之间的预测得分。这个得分大于 0.5 表示模型认为它是正面评论小于 0.5 表示负面。我一般会让你挑出几条极端错误的样本仔细看比如一条明显是“垃圾股”的评论被预测成 0.8 分大概率是分词阶段出了问题——“垃圾”这个词被切碎了或者“垃圾”根本没有出现在训练集里。这时候不要急着换模型先回看分词结果和特征权重找出模型预测错误的真实原因再决定下一步。4. 深度学习路线与情感指数计算从 LSTM 到 BI 曲线如果说机器学习路线是整个项目的“下限保底”那么深度学习路线就是“上限冲分”的部分。model_dl.py 负责用 Word2Vec 训练词向量再送入 LSTM 模型做序列分类compute_sent_idx.py 则把模型的输出概率与词典规则融合计算出可以和大盘走势对照的情感指数。4.1 Word2Vec 词向量与 LSTM 网络的结构设计import gensim from gensim.models import Word2Vec import numpy as np from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Embedding, LSTM, Dense # 用 jieba 分词后的句子列表训练 Word2Vec sentences [text.split() for text in df[cut_comment]] w2v_model Word2Vec(sentences, vector_size128, window5, min_count2, workers4) # 构建词表与嵌入矩阵 word_index {word: idx 1 for idx, word in enumerate(w2v_model.wv.index_to_key)} embedding_matrix np.zeros((len(word_index) 1, 128)) for word, idx in word_index.items(): embedding_matrix[idx] w2v_model.wv[word] # LSTM 模型结构 model Sequential() model.add(Embedding(input_dimlen(word_index) 1, output_dim128, weights[embedding_matrix], trainableFalse)) model.add(LSTM(units64, dropout0.2, recurrent_dropout0.2)) model.add(Dense(1, activationsigmoid)) model.compile(optimizeradam, lossbinary_crossentropy, metrics[accuracy])这里必须强调一个大多数初学者会踩的坑Embedding 层的 trainable 参数。刚开始做的时候我把 trainable 设置成了 True想让模型在训练过程中微调词向量结果在小样本数据上出现了严重的过拟合——训练集准确率到了 98%测试集却只有 62%。后来改成 trainableFalse让词向量保持预训练结果不变测试准确率反而稳定下来。原因是词向量的训练需要足够大的语料几百条评论根本不足以反向传播修正 128 维的向量空间。LSTM 的 units64 是隐藏状态维度。这个值不宜过大因为评论属于短文本单条评论分词后通常只有 10 到 30 个词过大的隐藏维度会带来大量冗余参数训练时间增加但效果不升反降。dropout 和 recurrent_dropout 都是 0.2用来防止过拟合。attention 机制在这个项目里不是必需的虽然加上它可能提升 1 到 2 个百分点的准确率但会增加代码长度和答辩时的解释负担。4.2 情感指数 BI 的计算原理compute_sent_idx.py 是这个项目区别于普通“情感分类 Demo”的关键所在。它做的事情是把某一天内所有评论的模型预测概率取平均值再结合词典得分进行修正最终得到该日的情绪指数。通常的做法是import pandas as pd import numpy as np scores pd.read_csv(model_ml_scores.csv, parse_dates[date]) scores[date] scores[date].dt.date # 按天聚合模型预测概率 daily_pred scores.groupby(date)[pred_score].mean().reset_index() daily_pred.columns [date, model_score] # 读入正向和负向词典计算当日评论中的词典情绪得分 positive_words set(open(positive.txt, encodingutf-8).read().split()) negative_words set(open(negative.txt, encodingutf-8).read().split()) def dict_score(text): pos_count sum(1 for w in text.split() if w in positive_words) neg_count sum(1 for w in text.split() if w in negative_words) if pos_count neg_count 0: return 0.5 return pos_count / (pos_count neg_count) # 词典得分和模型得分加权融合权重通常设置为 0.7 和 0.3 scores[dict_score] scores[comment].apply(dict_score) scores[blended_score] 0.7 * scores[pred_score] 0.3 * scores[dict_score] daily_blend scores.groupby(date)[blended_score].mean().reset_index() daily_blend.columns [date, BI] daily_blend.to_csv(BI_daily.csv, indexFalse)为什么要用 0.7 和 0.3 的加权比例而不是直接只用模型分数这是因为模型预测可能会有系统性偏差比如训练样本以“涨了”这类有明确正面词汇的评论为主那么遇到“回调”“出局”这类冷门负面表达时可能预测不准。词典分数虽然粗糙但它像一个保守的纠偏器——对极端词汇的响应是确定性的能够把模型的偏差拉回来一点。权重比例并非固定我一般会在 0.6:0.4 到 0.8:0.2 之间尝试然后看哪个比例下 BI 曲线与大盘走势的相关性更高就用哪个。4.3 可视化验证脚本 plot_sent_idx.pyplot_sent_idx.py 的核心产出是两张图。第一张 BI.png 是“情感指数随时间的变化曲线”横轴是日期纵轴是 BI 值范围在 0 到 1 之间大于 0.5 表示市场情绪偏乐观小于 0.5 表示偏悲观。第二张 BI_and_Market.png 是关键图它把 BI 曲线和上证指数曲线放在同一个坐标系里用双 Y 轴展示——左 Y 轴是 BI 值右 Y 轴是上证指数收盘价两条曲线叠在一起直观地展示“情绪领先于走势”或“情绪与走势同步”的关系。实际项目中用 matplotlib 的 twinx() 实现双 Y 轴是最省事的做法。绘制时建议对 BI 做 3 日移动平均平滑处理去掉单日噪声曲线会更耐看也更容易在答辩时讲出“趋势”。5. 避坑指南股市评论情感分析最容易翻车的五个地方每次带同学做这类项目我发现翻车点都惊人地一致。下面这五条是从真实项目里总结出来的“现象 → 原因 → 解决”对照着检查能省下你两三天调试时间。5.1 数据穿越评论日期和指数日期对不上现象BI_and_Market.png 画出来之后发现 BI 曲线整体向右偏移和大盘走势的对应关系看起来很混乱。原因评论数据的日期戳往往是在采集时生成的实际评论发布时间可能在几天前。直接按采集日期聚合等于引入了时间错位。这是个非常隐蔽的坑。解决在预处理阶段优先从评论内容的正则匹配中提取时间信息比如“03-15 10:22”这类前缀提取不到再回退到文件名或采集日期。计算日频 BI 之前先做一次日期对齐检查确认每一天都有足够数量的评论样本。5.2 算准率时使用不当的标签口径现象模型训练集在 jieba 分词后去掉停用词准确率从 70% 掉到 58%找不出原因。原因很可能是因为测试集存在大量此前未出现过的专有名词、股票代码简称比如“茅五泸”“宁王”这些词不在训练集里分词后变成单字碎片。解决不要急着删停用词。先保留一份“不分词”的原始文本做对照实验再给 jieba 增加自定义词典把“茅五泸”“宁王”这类股市专用词直接加入 user_dict让分词器将它们作为一个整体切分。准确率通常会回升 5 到 10 个百分点。5.3 深度学习模型的随机性问题现象同一个 LSTM 模型在同样的训练集上跑两次测试准确率相差 3% 左右答辩时无法复现。原因神经网络初始化、Dropout 随机丢弃、训练时的批次洗牌都会引入随机性。模型训练崩溃或准确率跳变时看起来完全随机的故障让人无从下手。解决在 model_dl.py 的训练入口设置固定随机种子np.random.seed(42)random.seed(42)tf.random.set_seed(42)。只要种子固定、数据顺序不改变多次运行结果就完全一致。毕业论文里一定要写明“在固定随机种子条件下复现”这是答辩时的加分细节。5.4 情感词典读取的编码问题现象compute_sent_idx.py 运行时报 UnicodeDecodeError或者词典里的词匹配不上文本。原因positive.txt 和 negative.txt 虽然内容看起来是中文但编码可能是 GBK 或 UTF-8 带 BOM而你在 open() 时没指定编码参数Python 使用了系统默认编码去读。解决统一强制指定编码打开所有文本文件。最稳妥的做法是先把两个词典文件全部另存为 UTF-8 without BOM然后在代码中写上 encodingutf-8。这一点虽然是最简单的修改但也是最常被人忽视的项目事故源。5.5 只报准确率不报结果分布现象答辩时导师问“你的模型对正面评论的召回率是多少负面评论呢”你翻开测试集结果后才发现99% 的预测结果都是正面。原因数据集中正面评论远多于负面评论现实情况也确实如此下跌时散户更倾向骂人模型学到的是“多数类优势”准确率高但实质上几乎无区分能力。解决训练完成后必须看 classification_report 输出的精确率、召回率、F1 分数确认负样本也有足够的召回率。如果严重失衡处理办法是在训练集抽样时做下采样undersampling或对上采样目标是把正负样本比例控制在不高于 3:1。这一点直接影响项目评价等级。6. 验收与答辩技巧导师最关注的三个维度和一条展示主线项目到了收尾阶段真正决定成绩的不是代码量而是你能不能在一张图和一个演示流程里把整条逻辑链讲清楚。我建议你把答辩准备按下面三个维度来组织。验收维度考察点你的呈现材料数据可信度数据来源、预处理、清洗流程stock_comments.zip 的样本截图、预处理前后的文本对比模型有效度准确率、召回率、与基线对比classification_report 输出、ML 与 DL 两种模型的对比表格结果可解释性情感指数是否与行情走势吻合BI_and_Market.png 双 Y 轴图表、关键时间节点的标注答辩时我按这套顺序做过多次演练推荐你也这样做先展示项目目录和代码结构让导师建立整体框架再打开 BI_and_Market.png指着图上某个局部放大窗口说“你看在指数快速下跌前的三天BI 曲线已经连续走低说明市场情绪提前反映了悲观预期。” 这种演示方式远比念代码更打动人。老一辈带项目时有个习惯每一版模型训练完成之后强制走一遍“数据量 → 特征 → 模型 → 结果 → 可视化 → 结论”六步检查每一步都要能说出来“这一版和上一版相比哪个参数变了、为什么变、效果变化了多少”。从那以后我每次训练模型都坚持记录实验日志哪怕只是简单的 Excel 表答辩时也能清晰回答“你怎么知道你的模型有进步”这类问题。这套方法如果你也能坚持两周相信你的项目交付质量会明显提升。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑