ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

微博评论情感分析:朴素贝叶斯与SVM双模型实战解析

微博评论情感分析:朴素贝叶斯与SVM双模型实战解析 简介基于朴素贝叶斯与支持向量机算法的微博评论情感分析可视化项目源码适合计算机相关专业学生作为课程设计或期末大作业参考也可供希望进行文本挖掘项目实战的初学者学习。压缩包共51个文件大小约17.79MB主要包含Python主程序数据采集、情感预测、SVM与朴素贝叶斯训练等、CSV格式评论数据集、多份中文停用词表、ECharts可视化HTML页面以及训练完成的模型文件目录结构清晰便于按模块理解。已有303人学习浏览。项目中完整覆盖了从微博热搜数据获取、文本预处理、特征提取到两种机器学习算法对比评估与可视化展示的全流程附有运行命令说明和流程图代码可直接运行能辅助读者快速上手真实的情感分析任务是完成高分大作业或巩固机器学习实操能力的实用资料。1. 微博评论情感分析期末项目一份能直接跑通的双模型源码在文本情感分析这个方向上期末大作业最常见的翻车点是「跑了一个公开数据集但模型、爬虫、可视化是三块断的」交上去的代码只有训练脚本能执行剩下全靠截图凑数。这份基于机器学习的微博评论情感分析项目源码不一样它把朴素贝叶斯和支持向量机两个算法分别跑完再用 pyecharts 输出可视化页面训练、预测、展示三端闭环。大三期末项目做到这个完整度评审给了 99 分是有道理的。无论你要交课程设计还是期末大作业这套代码都适合作为起点因为它的数据采集、特征工程、模型对比、可视化已经全部打通你要做的是把它改造成自己的东西而不是从零开始摸着石头过河。2. 拆解数据管道producer 与 consumer 在项目里的真实职责2.1 生产者消费者模式的落地形态拿到压缩包之后很多人第一眼会被weibo_top_producer.py和weibo_top_consumer.py这两个文件名吓到以为要搭建分布式消息队列。其实这里用的是典型的「生产者-消费者」设计模式生产者负责采集微博热搜评论数据消费者负责把原始数据清洗并落盘。项目里这两个脚本配合dataset/re_sentiment_data.csv使用如果你不想碰在线采集完全可以直接用现成的 CSV 文件走后续流程生产者消费者脚本可以留作扩展学习。# weibo_top_producer.py 核心骨架常见实现形态 import csv import time import json class WeiboProducer: def __init__(self, output_pathdataset/re_sentiment_data.csv): self.output_path output_path # 采集配置页面数、每页条数、请求间隔 self.max_pages 20 self.per_page 50 self.sleep_seconds 1.5 self.writer None def fetch_hot_search(self): 获取热搜榜单返回热搜词列表 常见做法是请求公开接口注意控制频率 一旦触发频控就退避不要硬扛。 url https://weibo.com/ajax/side/hotSearch # 这里省略请求细节实际代码里用的是 requests 固定 headers pass def fetch_comments(self, weibo_mid, page1): 拉取某条微博下的评论 核心参数是 mid微博唯一标识和 page页码 返回的 JSON 里 comments 字段就是评论文本列表。 pass def save_row(self, text, label): 按 文本,标签 格式写入 CSV label 用 0/1 表示0 为负向1 为正向 with open(self.output_path, a, encodingutf-8, newline) as f: writer csv.writer(f) writer.writerow([text, label])这段骨架展示了生产者脚本的核心职责控制采集频率、解析评论 JSON、落盘 CSV。sleep_seconds这个参数值得注意公开接口的限流一般在每秒 1-3 次设太短会把 IP 送进黑名单设太长采集效率又太低。1.5秒是采集场景里较为稳妥的起步值。如果你是第一次跑这个项目我建议先直接使用数据集里的现成 CSV把生产者脚本当作「学习素材」而不是「必经步骤」这样可以最大程度避开采集环节的随机性。2.2 数据文件与停用词资源的搭配逻辑数据清洗是整个情感分析项目里最容易被低估的环节。微博评论和新闻语料不一样它短、口语化严重、带 emoji、带 提及和话题标签如果不过滤这些噪声后续 TF-IDF 特征矩阵会全是无效词。项目里准备了五个词表资源各司其职文件作用使用建议哈工大停用词表.txt通用中文停用词主停用词表优先加载四川大学机器智能实验室停用词库.txt补充停用词和哈工大表合并去重后使用中文停用词库.txt通用兜底词表覆盖基础虚词、助词stopwords.txt英文停用词及数字过滤微博里混入的英文BosonNLP_sentiment_score.txt情感词典带极性分值可以结合规则做辅助验证# 停用词加载的常见写法 import jieba def load_stopwords(file_paths): 合并多个停用词表返回一个 set stopwords set() for path in file_paths: with open(path, r, encodingutf-8) as f: words [line.strip() for line in f.readlines()] stopwords.update(words) return stopwords stopword_files [ 哈工大停用词表.txt, 四川大学机器智能实验室停用词库.txt, stopwords.txt ] stopwords_set load_stopwords(stopword_files) def clean_text(text): 微博评论文本清洗 # 去除 提及、话题标签、链接、多余空白 text re.sub(r\w|#.*?#|http\S|\s, , str(text)) # jieba 分词 words jieba.lcut(text) # 过滤停用词、单字、纯数字 words [w for w in words if w not in stopwords_set and len(w.strip()) 1 and not w.isdigit()] return .join(words)分词和停用词过滤的顺序有讲究先去除 和话题标签再做 jieba 分词能显著降低分词错误率。比如「#开学第一课# 这也太燃了」如果不去掉话题标签jieba 会把这个 hashtag 当成一个名词特征空间里就多出一个没有情绪含义的噪声词。len(w.strip()) 1这个过滤条件是我个人习惯微博短文本里单个字基本没有判别力去掉之后特征矩阵稠密度反而提升。3. 模型训练TF-IDF 特征与朴素贝叶斯、SVM 的选型逻辑3.1 中文文本向量化为什么是 TF-IDF在把评论文本喂进模型之前必须先完成向量化。常见做法有 CountVectorizer词频计数、TF-IDF词频-逆文档频率和 Word2Vec词向量。这个项目选的是 TF-IDF原因很直接微博评论属于短文本单条评论平均只有二三十个字词向量在这种长度下很难学到上下文语义而 TF-IDF 能通过「逆文档频率」压低那些在每个样本里都出现的通用词的权重把「好吃」「难吃」「太棒」这类有情绪倾向的词凸显出来。# weibo_top_sentiment_SVM_bayes.py 核心训练逻辑 from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.naive_bayes import MultinomialNB from sklearn.svm import LinearSVC from sklearn.model_selection import train_test_split import pandas as pd import joblib # 读取清洗后的数据 df pd.read_csv(dataset/re_sentiment_data.csv, encodingutf-8) X_text df[text].values # 清洗后的评论文本 y_labels df[label].values # 0负向 1正向 # TF-IDF 向量化参数设计 tfidf TfidfVectorizer( max_features10000, # 只保留词频最高的前 1 万个特征 ngram_range(1, 2), # 同时考虑单个词和二元词组 sublinear_tfTrue, # 用 1log(tf) 替代原始词频平滑长文本影响 min_df2 # 至少在 2 个文档中出现过才保留 ) # 统一在训练集上 fit再 transform 测试集避免数据泄露 X tfidf.fit_transform(X_text) X_train, X_test, y_train, y_test train_test_split( X, y_labels, test_size0.2, random_state42, stratifyy_labels ) # 朴素贝叶斯适合高维稀疏文本训练快 nb_model MultinomialNB(alpha1.0) # alpha 是拉普拉斯平滑系数 nb_model.fit(X_train, y_train) print(NB accuracy:, nb_model.score(X_test, y_test)) # SVM使用线性核LinearSVC高维稀疏场景下效果好 svm_model LinearSVC(C1.0, losshinge, max_iter5000) svm_model.fit(X_train, y_train) print(SVM accuracy:, svm_model.score(X_test, y_test)) # 保存模型和向量器预测阶段要一起加载 joblib.dump(tfidf, tfidf_vectorizer.model) joblib.dump(nb_model, tfidf_nb_sentiment.model) joblib.dump(svm_model, tfidf_svm_sentiment.model)这段代码里有几个参数值得展开。ngram_range(1, 2)是为了捕捉「不」「好吃」这类否定结构——如果你只用单个词「不好吃」会被拆成「不」「好吃」情感倾向完全判断反了。min_df2是过滤那些只出现了一次的生僻词微博上大量一次性生成的网络流行语属于噪声保留它们只会让特征矩阵更稀疏。sublinear_tfTrue这个参数很多人会忽略它的作用是把词频做对数压缩词频 100 和词频 500 的差距在 log 变换后被压缩避免长评论主导特征权重。3.2 为什么同一份数据跑两个模型文本情感分析这个领域朴素贝叶斯和 SVM 是经典的对选手。两者的理论根基完全不同朴素贝叶斯基于概率图模型假设特征之间相互独立——这个假设在文本场景下明显不成立「好吃」和「非常好吃」其实高度相关但贝叶斯仍然能在这个「不成立的假设」下给出不错的结果因为它只需要正确的决策边界不需要准确的概率估计SVM 则是几何方法在高维空间中找一个最大间隔超平面对稀疏文本特征天然免疫。我用一句话概括选型理由朴素贝叶斯是上限不高但从不翻车的基线模型SVM 是文本分类里性价比最高的强模型。大作业展示这两个模型的对比技术上站得住脚答辩时也方便展开。你会在项目目录下看到tfidf_nb_sentiment.model和tfidf_svm_sentiment.model两个模型文件说明训练脚本已经把两套参数都跑完并落盘了。3.3 模型文件与训练脚本的对应关系# 模型加载与验证的标准姿势 import joblib from sklearn.metrics import classification_report # 加载保存的两个模型和向量器 tfidf joblib.load(tfidf_vectorizer.model) nb_model joblib.load(tfidf_nb_sentiment.model) svm_model joblib.load(tfidf_svm_sentiment.model) # 用自己的测试数据做验证而不是用训练时的测试集 new_texts [这部剧的演技太出彩了, 垃圾服务再也不来了, 一般般吧没想象中好] X_new tfidf.transform(new_texts) # 注意这里用 transform不是 fit_transform print(NB:, nb_model.predict(X_new)) print(SVM:, svm_model.predict(X_new))注意transform和fit_transform的区别。训练时对向量器调用fit_transform是为了让它学习整个语料库的词频分布和 IDF 权重预测阶段必须只调用transform用训练时学习到的词汇表做映射。如果预测时误用了fit_transform向量器会重新学习一套词汇表特征维度对不上模型直接崩溃或者给出完全错误的预测。4. 预测与可视化从模型加载到 pyecharts 出图4.1 预测脚本的输入输出设计weibo_top_sentiment_predict.py承担的是「新数据进来 → 输出情感标签」这个环节。它的输入可以是命令行指定的单条文本也可以是 CSV 文件里的批量文本。出于期末大作业演示的方便脚本通常会把预测结果写成带标签的 CSV再交给下一步的可视化脚本消费。# weibo_top_sentiment_predict.py 核心逻辑 import sys import pandas as pd import joblib from utils import clean_text # 复用清洗函数 def predict_file(input_path, output_pathresult/predict_result.csv): 批量预测 CSV 中的评论文本 df pd.read_csv(input_path, encodingutf-8) tfidf joblib.load(tfidf_vectorizer.model) svm_model joblib.load(tfidf_svm_sentiment.model) # 清洗 → 向量化 → 预测三步顺序不能乱 df[clean_text] df[text].apply(clean_text) X tfidf.transform(df[clean_text]) df[svm_label] svm_model.predict(X) # 保存预测结果供可视化脚本读取 df.to_csv(output_path, indexFalse, encodingutf-8-sig) def predict_single(text): 单条文本预测用于命令行演示 tfidf joblib.load(tfidf_vectorizer.model) nb_model joblib.load(tfidf_nb_sentiment.model) svm_model joblib.load(tfidf_svm_sentiment.model) clean clean_text(text) X tfidf.transform([clean]) nb_label nb_model.predict(X)[0] svm_label svm_model.predict(X)[0] return { text: text, nb_result: 正向 if nb_label 1 else 负向, svm_result: 正向 if svm_label 1 else 负向 }utf-8-sig编码是一个容易被忽略的细节。Windows 下的 Excel 打开无 BOM 的 UTF-8 CSV 时会乱码加上-sig后缀生成带 BOM 的文件中文就能正常显示。做大作业演示时评委大概率会直接打开你输出的 CSV 文件检查这一点做不好会被扣印象分。两个模型同时预测的设计也很有用——同一个文本你能直接看出朴素贝叶斯和 SVM 判定是否一致答辩时这就是一个天然的讨论点模型对哪类表达有分歧原因是什么。4.2 可视化脚本的图表逻辑weibo_top_visual_pyecharts.py是这个项目里最亮眼的部分。它读取预测结果生成两个关键图表情感分布饼图sentiment_ratio_pie_page_2.html和情感得分柱状图sentiment_score_bar_page_1.html输出到static目录下。# weibo_top_visual_pyecharts.py 核心逻辑 from pyecharts.charts import Pie, Bar from pyecharts import options as opts import pandas as pd def plot_sentiment_ratio(df): 情感占比饼图 counts df[svm_label].value_counts() data_pair [(正向, int(counts.get(1, 0))), (负向, int(counts.get(0, 0)))] pie Pie() pie.add( series_name情感分布, data_pairdata_pair, radius[40%, 70%], # 环形饼图内半径40%外半径70% label_optsopts.LabelOpts(formatter{b}: {d}%) ) pie.set_global_opts(title_optsopts.TitleOpts(title微博评论情感分布)) pie.render(static/sentiment_ratio_pie_page_2.html) def plot_score_bar(df): 正负样本量柱状图 得分排序 positive_count int((df[svm_label] 1).sum()) negative_count int((df[svm_label] 0).sum()) bar Bar() bar.add_xaxis([正向, 负向]) bar.add_yaxis(评论数量, [positive_count, negative_count]) bar.set_global_opts( title_optsopts.TitleOpts(title微博热搜评论情感得分), yaxis_optsopts.AxisOpts(name条数) ) bar.render(static/sentiment_score_bar_page_1.html)pyecharts 的一个好处是图表完全可交互鼠标悬停能看到具体数值这在期末答辩演示时比 matplotlib 的静态图效果好一个档次。radius[40%, 70%]制造环形效果既美观又能在内圈放标题这是汇报场景里的常见设计。你只需要双击打开生成的 HTML 文件就能看效果不需要起任何后端服务这个设计对答辩演示来说非常友好——不用现场配 Flask 环境也不用担心演示时端口被占。4.3 静态页面的数据流交付逻辑项目的templates/index.html是一个汇总入口页面它把两张图表和热搜分析说明整合到一起。你完全可以直接用浏览器打开index.html作为项目主页评委看到的是「一份结构化的大作业展示」而不是「一堆需要手动运行的脚本」。这个设计思路值得学习源码是给人看的但第一眼的演示效果决定了评委的初始印象分数。5. 避坑与常见问题排查编码、依赖、模型加载三座大山从命令行运行到演示出图整个链路里有几个坑是大概率会踩到的。我按「现象 → 原因 → 解决」逐条整理这些全部来自实际跑项目时的血泪经验。5.1 中文乱码Windows 控制台输出一堆问号现象在 Windows 命令行运行python weibo_top_sentiment_predict.py控制台打印的结果里中文全部变成???。原因Windows 的 CMD 默认编码是 GBK而 Python 3 的字符串默认输出编码是 UTF-8两者不匹配时控制台无法正确显示中文。这个问题在数据文件和代码注释里也同样存在——如果脚本里硬编码的中文路径在 Linux 下正常在 Windows 下就会因为编码问题抛 FileNotFoundError。解决在脚本入口处强制指定标准输出编码优先用 UTF-8 模式运行# Windows 下推荐用这个方式运行避免陷入编码地狱 set PYTHONIOENCODINGutf-8 python weibo_top_sentiment_predict.py # 或者更稳妥直接在脚本第一行声明 # sys.stdout.reconfigure(encodingutf-8)5.2 sklearn 版本差异导致模型文件加载失败现象运行预测脚本时抛出ModuleNotFoundError: No module named sklearn.svm._classes或ValueError: sklearn version mismatch。原因模型文件里序列化了训练时的 sklearn 类路径如果训练时的 scikit-learn 版本和当前环境版本差异过大比如 0.24 → 1.3新版 sklearn 改变了内部模块路径joblib 就无法定位到对应的类。这个坑最隐蔽因为代码本身没写错纯粹是环境版本问题。解决创建虚拟环境安装与模型匹配的 sklearn 版本。这个项目的模型文件保存时间和 Python 3.10 对应常见做法是安装 scikit-learn 1.2.x 系列。最保险的方案是直接重跑训练脚本在自己环境下生成新模型一劳永逸pip install scikit-learn1.2.2 joblib jieba pyecharts pandas python weibo_top_sentiment_SVM_bayes.py5.3 数据集行数过多导致训练内存爆炸现象跑训练脚本时 MemoryError或者 TF-IDF 向量化阶段卡死超过十分钟没反应。原因TfidfVectorizer默认会拟合全部特征当原始评论数据达到几十万条且未限制max_features时特征矩阵规模会膨胀到几万乘几十万对内存的消耗非常恐怖。解决先拿少量数据验证流程再全量训练。把原始 CSV 随机抽样 5000 条跑通整个链路确认准确率合理后再扩大数据量。如果要全量训练需要把max_features从 10000 降到 5000 左右观察准确率变化再决定是否加回。5.4 pyecharts 图表中文标签显示为方块现象生成的 HTML 图表中柱状图的中文标签全部变成小方块。原因pyecharts 渲染依赖 HTML 中的字体配置如果页面默认字体不支持中文就会出现方块。这个问题在 macOS 上几乎不会出现但 Windows 的某些浏览器默认字体配置会触发。解决在set_global_opts里显式指定中文字体bar.set_global_opts( title_optsopts.TitleOpts(title微博热搜评论情感得分), legend_optsopts.LegendOpts(textstyle_optsopts.TextStyleOpts(font_familyMicrosoft YaHei)) )5.5 爬虫脚本被频控采集到一半中断现象运行weibo_top_producer.py时前几千条正常之后就大量返回 403 或空数据。原因微博对公开接口有基于 IP 和 Cookie 的频控策略固定间隔地请求一段时间后请求频率仍会触发限制需要随机化间隔并随机更换 UA 头。解决不修改大量采集逻辑的前提下把固定sleep_seconds改为随机范围同时准备几个浏览器 UA 头随机切换。但更务实的建议是期末大作业不需要真正的海量数据用好项目自带的dataset/re_sentiment_data.csv和少量手动补充的评论数据就足够展示全流程了。6. 把项目改造成自己的大作业四个进阶动作拿到了这份能跑的源码最忌讳的就是原封不动交上去。答辩时老师问你「这个模型准确率为什么是 87%」你说不上来分数照样不高。把项目改造成自己的思路关键在于往里面加你自己的理解。第一个动作替换数据源。去 Kaggle 或 GitHub 上找一份带情感标签的中文评论数据集比如电商评论、外卖评论保持 CSV 的「文本,标签」两列格式直接喂给现有脚本。这一步替换能让项目从「微博评论情感分析」变成「电商评论情感分析」方向变了主题就是你自己的。数据量控制在 5000-20000 条之间既能保证训练效率又有足够样本支持模型评估。第二个动作加交叉验证和混淆矩阵。目前脚本用的是单次train_test_split结果有一定随机性。加 5 折交叉验证后就能算出准确率的均值和方差答辩时可以说「模型在五折交叉验证下平均准确率 87.3%标准差 1.2% 分」这比单次结果专业得多from sklearn.model_selection import cross_val_score from sklearn.svm import LinearSVC svm LinearSVC(C1.0, max_iter5000) scores cross_val_score(svm, X, y_labels, cv5, scoringaccuracy) print(5-fold CV accuracy: {:.4f} ± {:.4f}.format(scores.mean(), scores.std()))第三个动作输出分类报告。情感分析领域准确率不是唯一指标负向样本的召回率在舆情场景里同样关键。classification_report会输出每个类别的精确率、召回率和 F1 分数把这份报告贴进大作业文档里可视化和数据说服力都有了。第四个动作做一个对比实验表。用朴素贝叶斯和 SVM 分别测不同ngram_range下的准确率把结果整理成表格就能清楚回答「为什么选这两个模型」「参数调整对结果的影响」这类高频答辩问题。我自己过去被问过最尴尬的一个问题是「你的模型在真实数据上表现怎么样」当时我只用了测试集答不上来。后来养成一个习惯训练完模型后一定手动敲 5 条训练数据里没有的真实评论去预测把预测结果截图存下让模型接受「它没见过的话」的检验。从那以后我每次拿到机器学习项目都强制走一遍这个流程——模型再好看能扛住真实表达才算数。希望这份拆解能帮你在期末大作业里少走些弯路把项目真正跑通、跑懂、跑出自己的东西。本文还有配套的精品资源点击获取
返回列表