简介:本资源为基于Python的电商买家评论数据情感分析完整课程设计包,面向计算机、人工智能、软件工程等专业学生及教师,适合课程大作业、毕业设计或项目初期立项参考。包内共1379个文件,以478个py源码、237个csv评论数据集、178个txt说明、125个html页面及模型文件为主,压缩包约53.95MB,涵盖数据爬取、情感分类、主题建模与可视化全流程。项目选用美的热水器等多品牌商品评论,兼顾好评差评与时间跨度,涉及评论分数与内容不吻合、关键词提取、情感分数计算、装饰器计时与log、config配置、训练测试集划分等细节,并附代码注释与开发文档。运行入口为streamlit run ./Comment_analysis/Streamlit/streamlitEXP.py,可快速启动图形化界面演示。已有1119人学习下载,适合小白借鉴或在此基础上扩展BERT情感分类、pyLDAvis可视化等功能。
1. 从一份课程大作业说起:电商评论情感分析到底在做什么
打开任何一个电商平台的商品页,评论区里藏着大量真实用户反馈。有人写“质量很好,物流快,下次还来”,也有人写“收到货就后悔了,色差严重,客服还不理人”。对商家来说,这些文本是改进产品和运营的线索;对平台来说,是风控和推荐的重要信号。但靠人工一条条看,几万条评论根本翻不过来。基于 Python 的电商买家评论数据情感分析,要解决的就是这件事:把非结构化的中文评论自动分成正面、负面(有时还有中性),并给出可解释的置信度。这套源码+模型+数据集+代码注释的组合,适合正在做课程大作业的学生,也适合想快速搭一个评论分析原型的初级工程师。它不追求工业级吞吐,但胜在链路完整、注释清楚,能让你从数据读入一路跑到模型评估,把“情感分析”这四个字从概念变成能跑起来的代码。
2. 数据准备与中文评论预处理:从原始 CSV 到模型可吃的张量
2.1 拿到数据集先别急着训练,先看清三件事
课程大作业给的数据集通常是 CSV 或 Excel,字段一般包含评论内容、评分、时间、商品 ID。我拿到手第一件事不是写模型,而是用 pandas 做三查:查类别分布、查文本长度分布、查缺失值。电商评论有个特点,好评远多于差评,如果直接训练,模型会倾向于把所有评论判成正面,准确率看着高,但差评召回率惨不忍睹。所以先统计正负样本比例,后面再决定要不要做重采样或类别权重。
import pandas as pd df = pd.read_csv("ecommerce_comments.csv", encoding="utf-8") print(df["label"].value_counts()) # 看正负样本是否均衡 print(df["comment"].str.len().describe()) # 看文本长度,决定截断长度 print(df.isnull().sum()) # 看缺失值分布这段代码输出三个关键信息:类别分布决定是否要处理不均衡;长度分布决定 padding 的最大长度,一般取 95 分位数,避免为了几条超长评论浪费显存;缺失值决定是删除还是填充。参数上,encoding在 Windows 上常遇到 gbk,如果报 UnicodeDecodeError,换成gb18030基本能解决。
2.2 中文分词与停用词:jieba 的三种模式和自定义词典
中文不像英文有空格,必须分词。常见做法是用 jieba,它有三种模式:精确模式适合文本分析,全模式会把“乒乓球拍卖完了”切成“乒乓/乒乓球/球拍/拍卖/卖完/完了”,搜索引擎模式介于两者之间。情感分析我一般用精确模式,再加载一个电商领域的自定义词典,把“性价比”“物流快”“色差”这类词固定下来,避免被切碎。
import jieba jieba.load_userdict("ecommerce_dict.txt") # 每行一个词,如"性价比"、"物流快" stopwords = set(open("stopwords.txt", encoding="utf-8").read().splitlines()) def cut_text(text): words = jieba.lcut(str(text), cut_all=False) # 精确模式 return " ".join([w for w in words if w not in stopwords and len(w) > 1]) df["cut_comment"] = df["comment"].apply(cut_text)cut_all=False表示精确模式;len(w) > 1过滤单字,因为单字在情感分析里噪声大;停用词表要包含“的、了、是、就”这类高频无意义词。注意,不要用全模式,否则特征维度会爆炸,训练变慢且容易过拟合。
2.3 标签怎么定:评分映射还是人工标注
如果数据集自带评分(1 到 5 星),常见做法是 4 到 5 星映射为正面,1 到 2 星映射为负面,3 星丢弃或单独做中性类。但这里有个坑:有些用户打 5 星却写“还行吧”,文本和标签矛盾。课程大作业里如果数据量不大,建议抽样 200 条人工核对一下映射规则是否合理。如果数据集已经给了 label 字段,直接用,但要看清楚 0 代表正面还是负面,别训练完发现标签反了。
def score_to_label(score): if score >= 4: return 1 # 正面 elif score <= 2: return 0 # 负面 else: return -1 # 中性,后续可丢弃 df["label"] = df["score"].apply(score_to_label) df = df[df["label"] != -1].reset_index(drop=True)这段逻辑简单,但参数边界要根据实际评分分布调整。如果 3 星占比很高,直接丢掉会损失大量数据,可以考虑把 3 星归入负面或单独训练一个三分类模型。
3. 模型选型与训练:TextCNN、BiLSTM 和 BERT 到底选哪个
3.1 课程大作业的算力现实:先跑通 TextCNN
如果你只有笔记本 CPU 或者一块入门级显卡,别一上来就 BERT。TextCNN 结构简单、训练快、效果在电商评论这种短文本上并不差。它的思路是用不同尺寸的卷积核捕捉 n-gram 特征,比如“质量好”“不推荐”“物流太慢”这种局部模式。源码包里如果有 TextCNN 实现,重点看 embedding 维度、卷积核尺寸和 dropout 设置。
import torch import torch.nn as nn class TextCNN(nn.Module): def __init__(self, vocab_size, embed_dim=128, num_filters=128, kernel_sizes=[2,3,4], num_classes=2): super().__init__() self.embedding = nn.Embedding(vocab_size, embed_dim, padding_idx=0) self.convs = nn.ModuleList([ nn.Conv2d(1, num_filters, (k, embed_dim)) for k in kernel_sizes ]) self.dropout = nn.Dropout(0.5) self.fc = nn.Linear(num_filters * len(kernel_sizes), num_classes) def forward(self, x): x = self.embedding(x) # [batch, seq_len, embed_dim] x = x.unsqueeze(1) # [batch, 1, seq_len, embed_dim] x = [torch.relu(conv(x)).squeeze(3) for conv in self.convs] x = [torch.max_pool1d(i, i.size(2)).squeeze(2) for i in x] x = torch.cat(x, 1) x = self.dropout(x) return self.fc(x)embed_dim=128是常见起点,评论短文本够用;kernel_sizes=[2,3,4]分别捕捉二元、三元、四元词组;dropout=0.5防止过拟合。如果显存不够,把num_filters降到 64。训练时用 Adam,学习率 1e-3,batch size 64 或 128。
3.2 BiLSTM 适合捕捉否定和转折,但别忽略序列长度
电商评论里“质量不错,但是客服太差”这种转折句,TextCNN 的局部卷积可能只抓到“质量不错”。BiLSTM 按顺序读入,能保留上下文信息,对否定词和转折词更敏感。但 LSTM 训练慢,且对序列长度敏感。我一般把最大长度截到 128,超过的截断,不足的补零。
class BiLSTM(nn.Module): def __init__(self, vocab_size, embed_dim=128, hidden_dim=128, num_classes=2): super().__init__() self.embedding = nn.Embedding(vocab_size, embed_dim, padding_idx=0) self.lstm = nn.LSTM(embed_dim, hidden_dim, batch_first=True, bidirectional=True) self.fc = nn.Linear(hidden_dim * 2, num_classes) def forward(self, x): x = self.embedding(x) out, _ = self.lstm(x) out = out[:, -1, :] # 取最后一个时间步 return self.fc(out)bidirectional=True让模型同时看正向和反向上下文;取最后一个时间步是因为它聚合了整句信息。如果效果不好,可以改成对时间步做平均池化。注意 padding 的位置,用pack_padded_sequence能避免 padding 影响 LSTM 输出,但代码会复杂一些,课程大作业里可以先不引入。
3.3 想冲高准确率再上 BERT,但要算清显存和时间
BERT 在中文情感分析上通常比 TextCNN 高 3 到 5 个百分点,但代价是显存至少 8G 起步,训练时间翻几倍。如果作业允许用预训练模型,可以用bert-base-chinese,把分类层换成二分类。常见做法是冻结前几层,只微调后面几层,降低显存占用。
from transformers import BertTokenizer, BertForSequenceClassification tokenizer = BertTokenizer.from_pretrained("bert-base-chinese") model = BertForSequenceClassification.from_pretrained("bert-base-chinese", num_labels=2) inputs = tokenizer(df["comment"].tolist(), padding=True, truncation=True, max_length=128, return_tensors="pt")max_length=128覆盖绝大多数电商评论;truncation=True自动截断超长文本。训练时学习率要调小,一般 2e-5 到 5e-5,否则容易灾难性遗忘。如果显存不够,把 batch size 降到 16 或 8,再用梯度累积。
4. 避坑与排查:电商评论情感分析里最容易翻车的五件事
4.1 准确率 95% 但差评全漏:类别不均衡没处理
现象:训练完准确率很高,但拿几条差评测试,全判成正面。原因:好评样本远多于差评,模型学会了“全猜正面”这个偷懒策略。解决:在损失函数里加类别权重,nn.CrossEntropyLoss(weight=torch.tensor([1.0, 3.0])),或者对少数类做随机过采样。更稳妥的是看 F1 分数和混淆矩阵,别只看准确率。
4.2 分词后“不”字被停用词表删了:否定词丢失
现象:模型对“不好”“不满意”判断反了。原因:停用词表里包含了“不”,分词后否定词消失。解决:停用词表里必须保留否定词和程度副词,如“不、没、很、太、非常”。我一般会单独维护一个“情感保留词表”,在过滤时优先保留。
4.3 训练集和测试集来自同一批商品:数据泄漏
现象:测试集准确率奇高,换一批评论就崩。原因:划分数据时没有按商品 ID 分组,同一个商品的评论同时出现在训练集和测试集,模型记住了商品特征而不是情感。解决:用GroupShuffleSplit按商品 ID 划分,确保同一商品的评论只出现在一边。
4.4 学习率设成 0.1:模型直接不收敛
现象:loss 震荡或变成 nan。原因:学习率太大,梯度爆炸。解决:Adam 默认 1e-3,BERT 微调用 2e-5。如果 loss 变成 nan,先检查输入里有没有空字符串或异常字符,再降低学习率。
4.5 预测时忘了加model.eval():dropout 还在起作用
现象:同一句话预测两次结果不一样。原因:模型还在训练模式,dropout 随机丢弃神经元。解决:预测前加model.eval(),并用with torch.no_grad():包住推理代码,既保证结果稳定,又省显存。
5. 把模型用起来:批量预测、置信度过滤和持续迭代的小技巧
训练完模型只是第一步,真正要用起来,得把它接进一个能批量处理评论的脚本。我一般会写一个predict.py,读入 CSV,输出每条评论的预测标签和置信度,再用置信度做一层过滤:低于 0.7 的交给人工复核,高于 0.9 的直接入库。这样既能保证自动化效率,又不会让模棱两可的评论污染分析结果。
import torch import pandas as pd from torch.utils.data import DataLoader model.eval() results = [] with torch.no_grad(): for batch in DataLoader(test_dataset, batch_size=64): logits = model(batch["input_ids"]) probs = torch.softmax(logits, dim=1) preds = torch.argmax(probs, dim=1) for text, pred, prob in zip(batch["text"], preds, probs): results.append({ "comment": text, "label": int(pred), "confidence": float(prob[pred]) }) df_out = pd.DataFrame(results) df_out["need_review"] = df_out["confidence"] < 0.7 df_out.to_csv("predict_result.csv", index=False, encoding="utf-8-sig")torch.no_grad()关闭梯度计算,推理速度提升明显;confidence取的是预测类别的概率;need_review标记低置信度样本。encoding="utf-8-sig"保证 Excel 打开不乱码。这个脚本跑完,你就能拿着结果去写作业报告,或者给运营同学做初步筛选。
还有一个容易被忽略的点:模型不是训练一次就完事。电商评论的语言会变,今天流行“绝绝子”,明天流行“yyds”,旧模型可能没见过。我习惯每隔一个月把新评论抽样人工标注 200 条,加入训练集重新微调一轮。不用全量重训,只微调最后一层分类器,半小时就能跑完。这个习惯让我避免了好几次“模型突然变笨”的尴尬。希望帮到你。
本文还有配套的精品资源,点击获取