资讯动态

微博评论情感分析毕设实战:SVM、朴素贝叶斯、AdaBoost三模型全流程指南

发布时间:2026/10/13 11:30:33 来源:尧图企业网站定制
简介这套毕业设计项目围绕微博评论文本情感分析展开采用支持向量机、朴素贝叶斯与AdaBoost三种机器学习算法构建完整的分类模型与对比实验适合计算机相关专业学生用于毕业设计参考也适合希望入门文本情感分析的开发者学习。资源包共70个文件以31个Python脚本为主体涵盖数据清洗、分词、训练、测试与可视化另含15个npy模型权重、13个txt语料与词典、4个model模型文件以及一篇《基于AdaBoost算法的情感分析研究》Word文档总大小6.05MB结构清晰便于按模块查阅。目前已有382人学习下载。通过这套资源读者可系统掌握中文微博情感的预处理、特征表示、模型训练与评估流程深入理解SVM、朴素贝叶斯和AdaBoost的原理与适用场景并能对照源码与文档完成实验复现或二次开发。1. 微博评论文本情感分析为什么拿 SVM、朴素贝叶斯、AdaBoost 做毕设是稳妥路线微博评论文本情感分析是把评论内容自动归入正面或负面情绪类别的文本分类任务而 SVM、朴素贝叶斯NB、AdaBoost 三种经典算法并列在标题里基本就说明了这个毕设的定位不追求刷分而是把数据清洗、分词、特征工程、模型对比、文档整理这条完整链路走通。这个组合里的三个算法各有各的脾气放在同一份数据集上对比既能让论文有实验表格可写也能让答辩老师看到你不是只会调包。适合做这个题目的人有两类一类是学校要求必须有三类模型对比和完整实验记录另一类是想快速把中文 NLP 的基本功练一遍同时拿到一份可以直接扩展成论文素材的项目代码。下面按做项目的顺序拆解重点说怎么落地和在哪翻车。2. 数据准备与预处理微博评论从原始语料到干净分词语料2.1 数据从哪来公开语料与文件组织方式做情感分析第一步不是写模型而是把数据准备好。我不建议直接对着微博接口去抓实时评论反爬、登录、字段解析会占掉你大量时间毕设阶段不值得。常见做法是找一份公开的微博情感语料CSV 格式两列一列是评论文本一列是标签。标签用 0 和 1 表示负面和正面二分类最简单也最稳妥。拿到语料后先把项目文件结构定下来后面写文档时能省很多事。我习惯这么组织weibo_sentiment/ ├── data/ # 原始数据与清洗后的中间数据 │ ├── raw.csv │ └── clean.csv ├── src/ # 全部代码 │ ├── preprocess.py │ ├── train.py │ └── predict.py ├── models/ # 训练好的模型文件 ├── requirements.txt └── README.md为什么要把 raw.csv 和 clean.csv 分开保存因为清洗规则你一定会反复调每次重跑清洗脚本时如果原始数据已经被覆盖你就没办法对比清洗前后的差异。保留 raw 是给自己留后悔药。2.2 清洗规则先把评论里的噪音去掉微博评论是典型的中文短文本夹杂着 URL、用户名、话题标签、表情符号、英文单词、数字。这些内容对情感判断基本没有贡献反而会撑大特征空间所以第一步是把它们清掉。import pandas as pd import re df pd.read_csv(data/raw.csv, encodingutf-8) df df.drop_duplicates(subset[comment]) df df.dropna(subset[comment, label]) def clean_text(text): text re.sub(rhttp\S, , text) # 去 URL text re.sub(r[\w]{1,20}, , text) # 去 用户名 text re.sub(r#.*?#, , text) # 去 话题标签 text re.sub(r\[.*?\], , text) # 去 表情符号占位符 text re.sub(r[^\u4e00-\u9fa5a-zA-Z], , text) # 只保留中文和英文 text re.sub(r\s, , text).strip() return text df[clean_comment] df[comment].apply(clean_text) df.to_csv(data/clean.csv, indexFalse, encodingutf-8-sig) print(df.shape)逻辑说明drop_duplicates 去掉完全重复的评论dropna 去掉缺失标签的行。正则里最关键的是[^\u4e00-\u9fa5a-zA-Z]这一行它把标点、数字、特殊符号全部替换为空只留汉字和英文。之所以留英文是因为像“yyds”“zqsg”这类网络词在微博语境里有明确情感倾向全删了会损失信息。如果你做的电影评论等正式文本可以把英文也去掉。参数说明清洗用什么正则没有标准答案核心原则是“宁可少删不能删错”。我看到不少同学把[^\u4e00-\u9fa5]直接一删到底结果评论里只剩汉字表情符号和网络用语全部消失。对微博语料来说建议先用 5% 数据做抽样人工看一眼清洗后还剩什么再做取舍。2.3 分词与去停用词jieba 怎么用才能不伤特征中文没有天然空格模型不认识连续的字符序列必须分词。jieba 是中文分词的事实标准对微博这种口语化文本用默认模式就够了。import jieba stopwords set() with open(stopwords.txt, r, encodingutf-8) as f: for line in f: stopwords.add(line.strip()) def tokenize(text): words jieba.lcut(text) words [w for w in words if w.strip() and w not in stopwords and len(w) 1] return words df[tokens] df[clean_comment].apply(tokenize) df[token_text] df[tokens].apply(lambda x: .join(x)) df.to_csv(data/clean.csv, indexFalse, encodingutf-8-sig)逻辑说明jieba.lcut返回一个词列表比jieba.cut更适合后面直接操作。过滤条件里len(w) 1会去掉单字词因为单个汉字如“好”“坏”虽然可能有情感但在特征空间里噪音大于信号绝大多数单字词是停用词或语气词。token_text是把分词结果重新拼成空格分隔的字符串这一步是为后面TfidfVectorizer直接接收字符串输入做准备。参数说明停用词表不是越大越好。网上流传的几百行停用词表里包含了“不”“没”“别”这类否定词如果把它们加进停用词表“不好吃”会被切剩“好吃”情感方向直接反转。我做中文情感分析时停用词表只保留“的、了、是、在、和、啊、哦、嗯”这类没有情感色彩的虚词。这个点你必须自己验证翻车概率极高。3. 特征工程把分词结果变成 TF-IDF 向量3.1 词袋模型与 TF-IDF为什么短文本必须用 TF-IDF分词之后文本仍不能直接丢给模型需要数值化。词袋模型Bag of Words统计每个词在评论里出现的次数用词频向量表示一条评论。但微博评论里高频词几乎都是“今天”“这个”“真的”之类的情感动词光看词频会被带偏。TF-IDF 在词频基础上乘一个逆文档频率那些在少数评论里出现、有区分度的词会被放大而到处都出现的词会被压下去。对这个项目来说TF-IDF 是比词袋更稳的选择区别在TfidfVectorizer里加一个use_idfTrue参数默认就是开启的。3.2 TfidfVectorizer 的参数设置三个必调项from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.model_selection import train_test_split vectorizer TfidfVectorizer( max_features5000, ngram_range(1, 2), min_df2, sublinear_tfTrue ) X_train, X_test, y_train, y_test train_test_split( df[token_text], df[label], test_size0.2, random_state42, stratifydf[label] ) X_train_vec vectorizer.fit_transform(X_train) X_test_vec vectorizer.transform(X_test)逻辑说明fit_transform在训练集上完成词典构建transform只做映射。这个顺序不能搞反否则测试集信息会泄漏到训练过程里模型评估结果虚高答辩时被问到就露馅。stratifydf[label]按标签比例分层抽样保证训练集和测试集里的正负样本比例与原始数据一致。参数说明max_features5000只保留词频最高的 5000 个词。微博情感分类的特征维度不高5000 已经足够再大只会增加训练耗时。ngram_range(1, 2)保留单词和相邻双词。比如“太难吃了”会被拆出“难吃”这个双词比单独“难”“吃”更有判别力。min_df2只在 2 条及以上评论出现的词才保留过滤掉只出现一次的生僻词和拼写错误。sublinear_tfTrue用 1log(tf) 替代原始词频降低长评论里重复词的权重。3.3 训练集与测试集划分随机划分还是按时间划分微博评论天然带时间属性但毕设场景下随机划分就够用。按时间划分会让模型面对没见过的网络用语F1 会明显下滑除非你的选题本身和研究时间维度相关否则不要给自己加难度。划分比例 8:2 是默认选择如果数据量超过一万条可以调到 9:1让训练数据更充分。4. 三模型实现与关键参数朴素贝叶斯、SVM、AdaBoost 的代码落地4.1 朴素贝叶斯先用它跑通流程再谈优化朴素贝叶斯对高维稀疏文本向量非常友好训练速度极快几乎不需要调参是第一个要跑通的模型。用MultinomialNB它假设特征服从多项式分布正好对应 TF-IDF 的非负值。from sklearn.naive_bayes import MultinomialNB from sklearn.metrics import classification_report nb MultinomialNB(alpha1.0, fit_priorTrue) nb.fit(X_train_vec, y_train) y_pred nb.predict(X_test_vec) print(classification_report(y_test, y_pred, digits4))逻辑说明fit_priorTrue表示根据训练集里的正负样本比例学习先验概率。如果你的数据本身比较均衡保持默认即可。alpha1.0是拉普拉斯平滑系数防止某个词在训练集中没出现过导致概率为 0。这个参数一般不需要动数据量小时可以降到 0.5 试试如果 F1 没有明显变化就维持默认。注意朴素贝叶斯对特征之间的独立性假设在现实中不成立但在文本分类里这个“错误假设”反而让它在小样本下表现稳定。它通常不是三个模型里最好的但一定是最先出结果的。4.2 SVM线性核还是 RBF 核毕设阶段别纠结SVM 是中文情感分析的经典选择尤其是LinearSVC。文本经过 TF-IDF 映射后已经是高维稀疏向量线性核往往比 RBF 核效果更好训练也快一个数量级。from sklearn.svm import LinearSVC svm LinearSVC( C1.0, losssquared_hinge, max_iter2000, random_state42 ) svm.fit(X_train_vec, y_train) y_pred_svm svm.predict(X_test_vec) print(classification_report(y_test, y_pred_svm, digits4))逻辑说明LinearSVC是线性核 SVM 的快速实现不用在SVC(kernellinear)上等很久。C1.0是误分类惩罚系数调大容易过拟合调小容易欠拟合。losssquared_hinge相比默认的hinge在多数文本分类任务里收敛更稳损失值下降更平滑。max_iter2000是最大迭代次数如果训练结束有收敛警告就往上调。如果你手里的数据量在一万条以内可以试试SVC(kernelrbf)配合gammascale但要做好训练时间翻十倍的心理准备。我个人的经验是在 5000 维特征、两万条数据的规模下线性核足够打败 RBF 核而且训练只要十几秒。毕设阶段优先把线性结果做扎实RBF 放进论文的对比实验里即可。4.3 AdaBoost一定要换基学习器并注意稀疏矩阵AdaBoost 的核心思路是串行训练多个弱分类器让后一个分类器更关注前一个分错的样本。但这里有个新手几乎必踩的坑AdaBoostClassifier默认的基学习器是深度为 1 的决策树桩对 TF-IDF 稀疏向量也可以工作但效果一般。我一般会换成浅层决策树并设置class_weight应对不平衡数据。from sklearn.ensemble import AdaBoostClassifier from sklearn.tree import DecisionTreeClassifier base DecisionTreeClassifier( max_depth2, class_weightbalanced ) ada AdaBoostClassifier( estimatorbase, n_estimators120, learning_rate0.8, random_state42 ) X_train_dense X_train_vec.toarray() X_test_dense X_test_vec.toarray() ada.fit(X_train_dense, y_train) y_pred_ada ada.predict(X_test_dense) print(classification_report(y_test, y_pred_ada, digits4))逻辑说明estimator指定基学习器这里用深度为 2 的决策树比默认深度 1 的树桩更能捕捉双词组合特征。class_weightbalanced让决策树在分裂时自动补偿样本不平衡这比手动过采样省事。n_estimators120是弱分类器数量太少欠拟合太多在后期会过拟合噪音。learning_rate0.8控制每棵树的贡献调小它可以让模型更稳但要配更大的n_estimators。最后一个坑AdaBoost 的fit方法不接受稀疏矩阵直接训练至少在常见的 sklearn 版本里需要先.toarray()转成稠密矩阵。X_train_vec 是 8000 行 5000 列的稀疏矩阵转稠密后内存占用大约 300MB要确保你的运行环境够用。这也是为什么我把它放到最后训练避免一开始就占满内存。注意如果 sklearn 版本较旧AdaBoostClassifier的基学习器参数名是base_estimator新版本改成了estimator老环境下会直接报错先看报错再改参数名。5. 结果评估与避坑五条印象深刻的踩坑记录5.1 用同一个指标口径对比三个模型模型都训练完之后评估不能只看准确率。微博评论数据如果类别不平衡准确率会非常失真。用classification_report同时输出精确率、召回率和 F1并以加权 F1 作为三维对比的主指标。from sklearn.metrics import f1_score for name, y_pred in [(NB, y_pred), (SVM, y_pred_svm), (AdaBoost, y_pred_ada)]: f1 f1_score(y_test, y_pred, averageweighted) print(f{name}: F1 {f1:.4f})逻辑说明averageweighted计算每个类别的 F1 并按样本量加权求和适合不平衡数据。三个模型最后输出的 F1 就是你论文实验表格里最核心的一行数字。根据这个方向上的常见实验结果SVM 通常略高于朴素贝叶斯AdaBoost 如果基学习器调得好也能逼近前两者。如果你的结果出现“AdaBoost 碾压所有模型”这种异常先检查是不是数据泄漏。5.2 避坑一预测全部输出同一个类别现象训练完成后classification_report里只有一个类别有数值另一个类别精确率全是 0。原因数据标签严重不平衡比如负面评论占 95%模型发现全部预测为负面也能拿到 95% 准确率于是放弃了学习正面特征。解决先看df[label].value_counts()确认两类样本比例。比例超过 3:1 时在 SVM 里设置class_weightbalanced在朴素贝叶斯里手动调整class_prior并在评估时以 F1 为准而不是准确率。5.3 避坑二测试集上调用 fit_transform 导致特征维度不匹配现象训练正常测试时vectorizer.fit_transform(X_test)后模型报dimension mismatch。原因对测试集重新做了fit生成了与训练集完全不同的词典。解决测试集上只能用transform。一个更隐蔽的情况是你在完整数据集上先做了fit_transform再做train_test_split这会导致测试集信息参与词典构建也就是数据泄漏F1 看起来很高但真实落地效果很差。5.4 避坑三清洗时把否定词删了情感方向反转现象模型 F1 还行但拿真实评论“不好吃再也不来了”测试预测成了正面。原因停用词表里包含了“不”“没”“别”等否定词分词后“不好吃”变成“好吃”。解决检查停用词表把否定词和程度副词全部移除。我见过最离谱的情况是网上找的停用词表里有“不”训练出来模型对“不喜欢”预测为正面。停用词表一定要人工过一遍特别是做情感分析时否定词是特征不是噪音。5.5 避坑四AdaBoost 调参过度训练集 F1 逼近 1.0现象AdaBoost 在训练集上 F1 达到 0.98测试集只有 0.74。原因n_estimators太大比如超过 300模型把训练集的噪音样本也记住了。解决用学习曲线观察n_estimators从 50 到 200 之间测试集 F1 的变化选上升曲线的顶点而不是过拟合区间的末端。也可以给决策树基学习器增加max_depth1或者min_samples_leaf5限制单棵树的表达能力。5.6 避坑五模型文件保存后加载报错现象.joblib文件正常保存换一台电脑加载时报ValueError。原因scikit-learn 版本不兼容模型 pickle 文件在不同版本间不保证稳定。解决在requirements.txt里固定scikit-learn版本保存模型的同时把版本号写进文档。我在毕设最后阶段吃过这个亏答辩演示时才发现本地训练好的模型在演示机器上加载失败最后只能现场重训。教训是训练脚本要比加载脚本先跑通模型文件不要跨环境移动。6. 让项目文档和演示“活起来”一个能跑的预测脚本与文档布局三模型训练完并评估完项目只算完成了一半。最后还要把整个流程封装成一个可复用的预测脚本并整理出符合毕设要求的项目文档。这一步直接决定你答辩时能不能现场演示以及老师翻看代码时能不能快速找到关键内容。import joblib import jieba import re def clean_text(text): text re.sub(rhttp\S, , text) text re.sub(r[\w]{1,20}, , text) text re.sub(r\[.*?\], , text) text re.sub(r[^\u4e00-\u9fa5a-zA-Z], , text) return text.strip() def predict_sentiment(text, model_pathmodels/best_model.joblib): vec joblib.load(models/vectorizer.joblib) model joblib.load(model_path) text clean_text(text) words [w for w in jieba.lcut(text) if len(w) 1] x vec.transform([ .join(words)]) pred model.predict(x)[0] return 正面 if pred 1 else 负面 if __name__ __main__: print(predict_sentiment(这家店的服务真的太好了下次还来)) print(predict_sentiment(等了一个小时还没上菜差评))注意测试结果打印出来验证后建议直接替换成自己的反馈语句可以进行简单的控制台交互或把结果统计到表格中。此脚本中的逻辑写得比较直接读取别人的项目文件后检查模型文件和 vectorizer 文件是否都放在同一目录预测函数内部每次调用都会重新加载模型演示环境数据量小没关系线上才会预加载。这个函数其实已经把完整流程复现了。文档布局方面项目文档必须能支撑别人复现至少包含这几块内容一、项目说明和目录结构二、环境依赖列表三、数据来源及预处理方法四、特征构建与模型选择理由五、实验结果对比表六、每个脚本的运行方法。答辩老师翻源码时最关注的往往是“数据如何划分”“特征如何构建”因为这两块最容易出规范问题。还有一点是把我自己的训练习惯分享出来每个模型在训练前固定random_state把每次实验结果记到一张 Excel 表格里字段包括模型名、参数组合、训练时间、测试集 F1。这张表后面会直接作为论文附录的素材省去重新整理的精力。项目收尾时会强制自己跑一遍完整流程从原始 CSV 到最终代码输出全部重跑确保每一步都不依赖手动修改的中间文件。这个习惯让我避免过两次一次数据文件被覆盖一次模型文件忘保存。希望帮到你。本文还有配套的精品资源点击获取

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

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

免费获取报价 →
↑