
简介这份毕业设计资源包围绕“基于机器学习的商品评论情感分析”展开面向计算机、人工智能相关专业的学生及需要完成课程设计或毕设的开发者帮助其系统掌握从文本预处理到模型评估的完整NLP实践流程。包内共43个文件以14个Python脚本为核心配合7个CSV与2个XLS数据集、4个NPY及3个PKL序列化文件、2个H5模型权重、4个XML配置和1个YML参数文件等覆盖数据清洗、分词、词向量训练、SVM与LSTM建模、GUI界面及爬虫采集等模块压缩包约66.66MB。项目完整呈现了词袋、TF-IDF、Word2Vec等特征提取方法以及朴素贝叶斯、SVM、LSTM等模型的训练与调参思路并附带混淆矩阵、ROC曲线等可视化脚本。目前已有166人学习适合作为情感分析入门到实战的参考范例也可直接用于二次开发与报告撰写。1. 商品评论情感分析从爬虫到模型部署一个毕业设计项目的完整落地路径电商平台上一条差评的破坏力往往抵得过一百条好评带来的信任积累。很多做计算机毕业设计的同学选到「基于机器学习的商品评论情感分析」这个题目时第一反应是“二分类任务调个 sklearn 就完事了”真正动手才发现中文评论里“质量不错但是物流太慢”这种混合情感怎么标标注数据从哪来模型在测试集上 92% 的准确率一上线跑真实评论就翻车为什么这个项目要解决的核心问题是把非结构化的中文评论文本自动映射为正面/负面有时还包括中性的情感极性并且让整个流程可复现、可解释、可展示。它适合计算机、软件工程、大数据方向的本科毕业生也适合刚入门 NLP 想找一个完整项目练手的工程师。下面我按自己带过几届毕设的经验把这个项目从数据到部署的完整路径拆开讲。2. 数据从哪来、怎么标商品评论语料的获取与清洗2.1 评论数据的三个来源与取舍做情感分析数据质量决定天花板。常见做法有三条路公开数据集、平台爬取、人工构造。公开数据集里ChnSentiCorp中文酒店评论和 online_shopping_10_cats10 类商品评论是毕设里用得最多的优点是标注现成、格式干净缺点是领域单一、句子偏短模型容易过拟合到“很好”“太差”这类高频词上。平台爬取能拿到最新、最真实的评论但要注意只采集公开可见的文本内容控制请求频率不涉及任何用户隐私字段。人工构造适合补充长尾场景比如数码产品的“续航虚标”、服装的“尺码偏小”但成本高一般只标几百条做测试集。我的建议是用公开数据集做训练主力爬取 20003000 条真实评论做验证集人工标注 300 条做最终测试。这样既有数据量又能暴露模型在真实分布上的问题。2.2 中文评论清洗的五个必做步骤原始评论里全是噪声直接喂给模型等于给自己挖坑。下面这段清洗代码是我每次都会用的基础版本import re import jieba def clean_chinese_text(text): # 1. 去除 HTML 标签和 URL text re.sub(r[^], , text) text re.sub(rhttp[s]?://\S, , text) # 2. 去除表情符号和特殊字符保留中文、英文、数字和基本标点 text re.sub(r[^\u4e00-\u9fa5a-zA-Z0-9。、], , text) # 3. 全角转半角数字和字母统一 text text.replace(, 0).replace(, 1) # 实际项目用 str.maketrans 批量处理 # 4. 去除连续重复字符如“好好好好好” text re.sub(r(.)\1{2,}, r\1\1, text) # 5. 结巴分词过滤单字和停用词 stopwords set([的, 了, 是, 在, 我, 有, 和, 就, 不, 人, 都, 一, 一个]) words [w for w in jieba.lcut(text) if len(w) 1 and w not in stopwords] return .join(words) # 示例 raw 这个商品质量很好但是物流太慢了 https://example.com print(clean_chinese_text(raw)) # 输出商品 质量 很好 但是 物流 太慢这段代码的逻辑说明第一步去 HTML 和 URL 是防止爬虫残留第二步的正则只保留中文、英文、数字和中文标点把 emoji 和乱码清掉第三步全角转半角避免“”和“123”被当成不同 token第四步处理“好好好好好”这类刷屏评论避免词频失真第五步分词后过滤单字和停用词减少特征维度。参数上要注意len(w) 1这个阈值不是绝对的像“差”“好”这种单字其实有强情感极性如果你的数据集里单字情感词占比高可以放宽到len(w) 1但要在验证集上看效果。停用词表建议用哈工大停用词表做基础再根据你的品类补充比如卖服装的要把“尺码”“颜色”加进去因为它们在所有评论里都高频出现区分度低。2.3 标注一致性三个人标出三种结果怎么办如果项目需要自己标注最大的坑是标注标准不统一。我一般会先写一份标注手册明确三条规则第一混合情感以整体倾向为准“质量好但物流慢”如果整体语气是抱怨标负面第二反讽和疑问句单独讨论“这质量也是没谁了”要结合上下文判断第三中性评论纯描述、无情感词单独设一类不要强行归入正负。标注时让两个人独立标 200 条算 Kappa 系数低于 0.7 就坐下来对齐标准别急着标全量。3. 特征工程与模型选型TF-IDF、Word2Vec 还是 BERT3.1 传统机器学习方案TF-IDF 线性模型毕业设计里最稳的方案是 TF-IDF 加逻辑回归或 SVM。原因很简单训练快、可解释、调参少答辩时能说清楚每个特征的含义。下面是一个完整的训练脚本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 import pandas as pd # 假设 df 有 text 和 label 两列label 为 0/1 df pd.read_csv(clean_comments.csv) X_train, X_test, y_train, y_test train_test_split( df[text], df[label], test_size0.2, random_state42, stratifydf[label] ) # TF-IDF 向量化 vectorizer TfidfVectorizer( max_features5000, # 保留词频最高的 5000 个词 ngram_range(1, 2), # 考虑单字和双字组合 min_df3, # 至少出现在 3 篇文档中才保留 max_df0.8, # 出现在超过 80% 文档中的词丢弃 sublinear_tfTrue # 用 1log(tf) 替代原始词频 ) X_train_vec vectorizer.fit_transform(X_train) X_test_vec vectorizer.transform(X_test) # 逻辑回归 clf LogisticRegression(C1.0, max_iter1000, class_weightbalanced) clf.fit(X_train_vec, y_train) y_pred clf.predict(X_test_vec) print(classification_report(y_test, y_pred))参数说明max_features5000是经验值评论数据一般 30008000 条5000 维足够覆盖主要情感词ngram_range(1,2)能捕捉“不 好”“太 差”这类否定和程度组合对情感分析很关键min_df3过滤只出现一两次的噪声词max_df0.8去掉“商品”“东西”这种几乎所有评论都有的词sublinear_tfTrue抑制高频词权重避免“好”字出现 100 次就主导整个向量。class_weightbalanced在正负样本不均衡时自动调整权重评论数据里正面往往多于负面这个参数能明显提升召回率。3.2 深度学习方案BERT 微调值不值得上如果你的毕设想冲优秀或者导师明确要求用深度学习BERT 微调是当前最成熟的选择。但要注意BERT 需要 GPU训练时间长调参空间大答辩时如果说不清 attention 机制反而容易被问住。我的建议是传统方案做 baselineBERT 做对比实验论文里写清楚两者在准确率、F1、训练时间上的差异这样既有工作量又有深度。用 HuggingFace 的 transformers 库微调中文 BERT 的核心代码from transformers import BertTokenizer, BertForSequenceClassification, Trainer, TrainingArguments import torch from torch.utils.data import Dataset class CommentDataset(Dataset): def __init__(self, texts, labels, tokenizer, max_len128): self.texts texts self.labels labels self.tokenizer tokenizer self.max_len max_len def __len__(self): return len(self.texts) def __getitem__(self, idx): encoding self.tokenizer( self.texts[idx], truncationTrue, paddingmax_length, max_lengthself.max_len, return_tensorspt ) return { input_ids: encoding[input_ids].squeeze(), attention_mask: encoding[attention_mask].squeeze(), labels: torch.tensor(self.labels[idx], dtypetorch.long) } tokenizer BertTokenizer.from_pretrained(bert-base-chinese) model BertForSequenceClassification.from_pretrained(bert-base-chinese, num_labels2) training_args TrainingArguments( output_dir./results, num_train_epochs3, # 评论数据 3 轮足够多了容易过拟合 per_device_train_batch_size16, # 显存 8G 以下用 8 learning_rate2e-5, # BERT 微调经典学习率 warmup_ratio0.1, # 前 10% 步数做 warmup weight_decay0.01, evaluation_strategyepoch, save_strategyepoch, load_best_model_at_endTrue )关键参数max_len128覆盖绝大多数评论长度超过的截断不够的补零num_train_epochs3是经验值评论数据量小5 轮以上基本过拟合learning_rate2e-5是 BERT 微调的标准起点太大容易震荡太小收敛慢warmup_ratio0.1让学习率在前 10% 步数里线性上升避免一开始就大步长破坏预训练权重。如果你的显存不够把 batch_size 降到 8同时把 gradient_accumulation_steps 设为 2效果等价。3.3 模型选型的决策表方案数据量要求训练时间准确率评论数据可解释性适合场景TF-IDF LR1000秒级85%90%强毕设 baseline、快速验证Word2Vec LSTM5000分钟级88%92%中想展示深度学习能力BERT 微调2000小时级92%96%弱冲优秀、有 GPU选型原则如果时间紧、机器差TF-IDF 方案足够毕业如果想发小论文或评优BERT 做主力传统方案做对比。不要为了用深度学习而用答辩老师更看重你能否解释清楚为什么选这个方案。4. 避坑与排查情感分析项目里最容易翻车的五个地方4.1 准确率 95% 但预测全是正面现象测试集准确率很高但混淆矩阵显示负面样本几乎全被预测成正面。原因正负样本不均衡正面评论占 80% 以上模型学会了“全猜正面”就能拿高准确率。解决用 F1 分数替代准确率做主指标训练时加class_weightbalanced或者对负面样本做随机过采样。更彻底的做法是分层采样划分数据集保证训练集和测试集的正负比例一致。4.2 分词把“不好”切成“不”和“好”现象模型把“不好”识别成正面因为“好”是强正面词。原因jieba 默认分词会把“不好”拆开TF-IDF 里“不”和“好”各自成特征丢失了否定含义。解决在 jieba 里加载自定义词典把“不好”“不错”“不差”这类否定组合加进去或者用ngram_range(1,2)让“不 好”作为一个二元特征进入模型。BERT 方案不存在这个问题因为 tokenizer 是按字切分能保留上下文。4.3 爬虫数据里混入大量重复评论现象训练集里“此用户没有填写评价”出现几千次模型把这个词学成了强特征。原因电商平台默认好评和刷单评论大量重复。解决清洗时用df.drop_duplicates(subset[text])去重同时把“此用户没有填写评价”“默认好评”这类模板文本加入黑名单直接过滤。如果重复率超过 30%说明数据源有问题考虑换品类或换平台。4.4 BERT 微调后验证集 loss 震荡不收敛现象训练 loss 正常下降验证 loss 上下跳动准确率卡在 85% 上不去。原因学习率太大、batch_size 太小、或者数据标注噪声太大。解决先把 learning_rate 降到 1e-5 试一轮如果还震荡检查标注数据里有没有明显标错的样本。另外warmup_ratio调到 0.2 也能缓解初期震荡。如果数据量少于 2000 条建议冻结 BERT 前 6 层只微调后 6 层减少过拟合风险。4.5 部署时预测结果和测试集不一致现象离线测试 F1 0.92写成一个 Flask 接口后同样的输入返回不同结果。原因训练时用了jieba.lcut分词部署时忘了加载自定义词典或者 TF-IDF 的 vectorizer 没有保存重新 fit 了一遍导致词表不一致。解决用joblib.dump把 vectorizer 和模型一起保存部署时joblib.load加载保证预处理和训练完全一致。BERT 方案要把 tokenizer 和模型一起保存到同一个目录。5. 从脚本到系统用 Flask 搭一个可演示的情感分析接口5.1 最小可运行的服务端代码毕设答辩时老师最想看的是“能不能跑起来”。下面是一个 Flask 接口加载训练好的模型接收评论返回情感极性from flask import Flask, request, jsonify import joblib import re import jieba app Flask(__name__) # 加载训练时保存的 vectorizer 和模型 vectorizer joblib.load(tfidf_vectorizer.pkl) model joblib.load(lr_model.pkl) # 加载自定义词典保证分词和训练一致 jieba.load_userdict(custom_dict.txt) stopwords set(open(stopwords.txt, encodingutf-8).read().splitlines()) def preprocess(text): text re.sub(r[^], , text) text re.sub(r[^\u4e00-\u9fa5a-zA-Z0-9], , text) words [w for w in jieba.lcut(text) if w not in stopwords and len(w) 1] return .join(words) app.route(/predict, methods[POST]) def predict(): data request.get_json() text data.get(comment, ) if not text: return jsonify({error: empty comment}), 400 cleaned preprocess(text) vec vectorizer.transform([cleaned]) pred model.predict(vec)[0] prob model.predict_proba(vec)[0].max() return jsonify({ sentiment: positive if pred 1 else negative, confidence: round(float(prob), 4) }) if __name__ __main__: app.run(host0.0.0.0, port5000)逻辑说明preprocess函数必须和训练时的清洗逻辑完全一致否则特征分布偏移会导致预测失准。vectorizer.transform而不是fit_transform因为词表已经固定。返回结果里带上置信度方便前端做阈值过滤比如置信度低于 0.6 的显示“中性”或“待人工确认”。参数上port5000是 Flask 默认端口如果被占用改成 5001。生产环境不要用app.run用 gunicorn 启动gunicorn -w 4 -b 0.0.0.0:5000 app:app4 个 worker 足够应付答辩演示。5.2 前端展示与可视化建议答辩时纯接口演示不够直观建议加一个简单的 HTML 页面输入评论实时显示情感标签和置信度进度条。如果想让图表更好看可以用 ECharts 画一个情感分布饼图把最近 100 条预测结果按正负统计。注意前端只做展示不要在前端做任何模型推理所有计算都在后端完成。5.3 性能优化的两个实用技巧第一如果 QPS 要求不高答辩场景基本没要求不用做批量推理单条预测延迟在 50ms 以内就够。第二如果模型是 BERT启动时加载模型需要几秒建议在 Flask 启动前就加载好不要放在请求里加载。可以用app.before_first_request或者直接在模块顶层加载。6. 让模型真正可用的三个进阶技巧第一个技巧是置信度阈值调优。默认的predict返回 0 或 1但predict_proba能给你概率。我一般会在验证集上画一条 precision-recall 曲线找到 F1 最大的阈值点而不是固定用 0.5。评论数据里阈值调到 0.6 往往能过滤掉一批模棱两可的样本让线上准确率更高。代价是有一部分评论会被判为“不确定”需要人工兜底但这比强行分类错要好。第二个技巧是错误分析驱动迭代。模型上线后把预测置信度在 0.50.6 之间的样本单独存下来每周人工看一遍把标错的加回训练集重新训练。这个闭环跑两三轮F1 通常能涨 35 个百分点。我带的上一届学生就是靠这个把 F1 从 0.87 拉到了 0.92答辩时老师问“你怎么证明模型在迭代”他直接拿出三轮的错误样本分析表效果很好。第三个技巧是领域适配。如果你做的是数码产品评论但拿酒店评论训练效果肯定打折。解决办法是用酒店数据预训练一个基础模型然后用数码评论做微调哪怕只有几百条标注也能明显提升。具体做法先在全量酒店数据上训一个 TF-IDF LR把 vectorizer 固定然后在数码评论上只更新分类器权重。BERT 方案更简单直接加载预训练权重在数码数据上跑 12 轮微调即可。技巧预期收益实施成本适用阶段置信度阈值调优F1 1%2%低模型训练完成后错误分析闭环F1 3%5%中上线后持续迭代领域适配微调F1 5%10%中高跨领域部署时最后说一个我自己的习惯每次训练完模型我都会把验证集里预测错的 20 条样本打印出来逐条看是标注错了、分词错了还是模型真的学不会。这个习惯帮我省了很多盲目调参的时间。希望帮到你。本文还有配套的精品资源点击获取