简介:本资源为基于Python的电商产品评论数据情感分析完整项目源码,面向计算机、自动化等专业学生及从业者,适用于课程设计、大作业与毕业设计场景。项目以真实电商平台评论为数据源,围绕情感倾向分析、评分与评论内容吻合度、关键词提取等核心问题展开,并配套需求文档、接口文档、流程图与开发规范说明,帮助读者理解从数据采集到可视化呈现的完整链路。压缩包共1380个文件,以478个py源码、237个csv数据集、178个txt说明、125个html页面为主,另含模型文件与词云、LDA主题可视化相关资源,整体约53.95MB,目录结构清晰便于按模块检索。项目已获1697人学习下载,评审分达95分,代码经严格调试可运行,读者可参考其数据划分、装饰器计时与日志、config配置及Streamlit图形化界面等实现,快速搭建同类情感分析系统。
1. 从一份课程大作业说起:电商评论情感分析到底在做什么
你手上有一份电商平台的评论数据,几千条到几万条不等,每条后面跟着一段用户随手敲下的文字。运营想知道这批货的口碑到底怎么样,产品想知道差评集中在哪个环节,而你要做的,是把这些非结构化的中文短文本变成可以统计、可以画图、可以下结论的标签。这就是电商产品评论情感分析要解决的核心问题:把「好评」「差评」「中评」从自然语言里抽出来,变成机器能算的东西。
这份基于 Python 的课程大作业,本质上是一条完整的流水线:读数据、清洗中文文本、分词、去停用词、把词变成向量、训练分类模型、评估效果、可视化结果。它适合两类人:一类是正在找 Python 课程设计或大作业选题的学生,需要一份能跑通、能讲清楚、能改参数的完整代码;另一类是刚接触 NLP 的开发者,想用一个真实场景把 jieba、scikit-learn、pandas 这条链路串起来。热搜里常出现的「python 入门」「python 安装」「python 安装 numpy 库的方法」,恰恰说明很多人卡在环境这一步,所以后面我会把环境、依赖、数据格式这些容易翻车的地方讲透。
2. 环境搭建与数据准备:别让第一步就劝退
2.1 Python 版本与依赖库的选型理由
做中文情感分析,Python 3.8 到 3.11 都能跑,但我不建议用太新的版本,因为某些分词和机器学习库的轮子还没跟上。常见做法是锁定 Python 3.9 或 3.10,配合虚拟环境,避免和系统里其他项目的包打架。核心依赖就四个:pandas 负责读表和清洗,jieba 负责中文分词,scikit-learn 负责特征提取和模型训练,matplotlib 或 pyecharts 负责出图。如果你还想做词云,再加一个 wordcloud。
安装命令不复杂,但顺序和源很关键。国内直接 pip 装有时候会卡在下载,换成清华源会稳很多。下面这段命令我一般会直接贴给同学:
# 创建虚拟环境,避免污染全局 python -m venv venv # 激活虚拟环境:Windows 用 venv\Scripts\activate,macOS/Linux 用 source venv/bin/activate source venv/bin/activate # 用国内镜像安装核心依赖,指定版本减少兼容问题 pip install pandas==1.5.3 jieba==0.42.1 scikit-learn==1.2.2 matplotlib==3.7.1 -i https://pypi.tuna.tsinghua.edu.cn/simple # 可选:词云库 pip install wordcloud==1.9.1 -i https://pypi.tuna.tsinghua.edu.cn/simple这里每个参数都有意义。python -m venv venv创建独立环境,后面所有包都装在这个目录里;-i指定镜像源,解决下载慢的问题;版本号锁定是为了避免 scikit-learn 新版本某些 API 改名导致代码报错。如果你装 numpy 时报错,大概率是 pip 版本太旧,先执行python -m pip install --upgrade pip再重试。
2.2 评论数据的字段设计与读取
课程大作业的数据通常来自爬虫或者公开数据集,格式多为 CSV 或 Excel。一份能直接用于情感分析的评论表,最少要有两列:一列是评论文本,一列是情感标签。标签可以是 0/1 二分类,也可以是 1/0/-1 三分类。如果你拿到的原始数据只有评分没有标签,可以用评分映射:4 到 5 星记作正面,1 到 2 星记作负面,3 星看情况丢弃或单独处理。
读取和初步检查的代码如下:
import pandas as pd # 读取 CSV,注意编码,中文数据常见 utf-8 或 gbk df = pd.read_csv('comments.csv', encoding='utf-8') # 如果报 UnicodeDecodeError,换成 gbk 再试 # df = pd.read_csv('comments.csv', encoding='gbk') # 查看前 5 行和字段类型 print(df.head()) print(df.dtypes) # 检查缺失值,评论为空的行直接删掉 df = df.dropna(subset=['comment', 'label']) # 统一标签类型为整数 df['label'] = df['label'].astype(int) # 看下正负样本分布,严重不均衡后面要处理 print(df['label'].value_counts())逻辑说明:dropna只删评论或标签为空的行,不要用dropna()全表删,否则可能误删其他有用字段。value_counts()是必看的一步,如果正面 9000 条、负面 500 条,模型会倾向于全猜正面,准确率看着高但没意义。参数上,encoding是最容易踩的坑,Windows 下导出的 CSV 经常是 gbk,Linux 和 macOS 多为 utf-8,读之前可以用记事本或file命令确认。
提示:数据量少于 500 条时,情感分析结果波动会很大,建议至少准备 2000 条以上再谈模型效果。
3. 中文文本清洗与分词:决定模型上限的一步
3.1 评论噪声的常见类型与清洗规则
电商评论和新闻语料不一样,它短、口语化、夹杂大量噪声。常见的噪声有:HTML 标签、URL、表情符号、重复标点、无意义数字、客服话术模板。清洗的目标不是把文本变干净到完美,而是去掉那些对情感判断没有帮助、反而干扰分词的内容。比如「这个价格????」里的问号不表达情感,但「质量太差了!!!」里的感叹号有强度信息,所以标点不能一刀切全删,我一般保留感叹号和问号,其余转成空格。
清洗函数可以这样写:
import re def clean_text(text): # 去掉 HTML 标签 text = re.sub(r'<[^>]+>', '', text) # 去掉 URL text = re.sub(r'http[s]?://\S+', '', text) # 去掉邮箱 text = re.sub(r'\S+@\S+', '', text) # 只保留中文、英文、数字和感叹号问号 text = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9!?]', ' ', text) # 多个空格合并成一个 text = re.sub(r'\s+', ' ', text).strip() return text df['clean_comment'] = df['comment'].apply(clean_text) print(df[['comment', 'clean_comment']].head(10))正则[^\u4e00-\u9fa5a-zA-Z0-9!?]的意思是:除了中文、英文字母、数字、中文感叹号和问号,其他字符全部替换成空格。\u4e00-\u9fa5是常用汉字的 Unicode 范围。这一步做完,你会发现很多「好评」「差评」里的表情和特殊符号被清掉了,分词质量会明显提升。
3.2 jieba 分词与停用词表的配合
中文不像英文有空格,必须分词。jieba 有三种模式:精确模式、全模式、搜索引擎模式。情感分析一般用精确模式,因为它切分最符合语义。但光分词不够,还要去停用词。停用词就是「的」「了」「是」「在」这类高频但无情感指向的词,留着只会增加维度、拖慢训练。
import jieba # 加载停用词表,一行一个词 with open('stopwords.txt', 'r', encoding='utf-8') as f: stopwords = set([line.strip() for line in f if line.strip()]) def cut_words(text): # 精确模式分词 words = jieba.lcut(text) # 过滤停用词、单字、纯数字 words = [w for w in words if w not in stopwords and len(w) > 1 and not w.isdigit()] return ' '.join(words) df['cut_comment'] = df['clean_comment'].apply(cut_words) print(df[['clean_comment', 'cut_comment']].head(10))参数说明:len(w) > 1过滤掉单字,因为单字在中文里歧义太大;not w.isdigit()去掉纯数字,价格数字对情感判断帮助有限。停用词表可以自己整理,也可以从公开的中文停用词表里拿一份,但要注意别把「不」「没」「别」这种否定词删掉,否则「不好」会变成「好」,情感直接反转。这是血泪经验,很多同学跑出来准确率异常高,就是因为否定词被误删了。
注意:停用词表里千万不要包含否定词和程度副词,如「不」「没」「很」「太」「非常」,它们对情感强度至关重要。
4. 特征提取与模型训练:从词袋到 TF-IDF 的取舍
4.1 词袋模型和 TF-IDF 到底选哪个
分词完成后,文本还是字符串,模型不认识。必须把文本转成数值向量。最常用的两种方式是词袋模型和 TF-IDF。词袋模型只看词出现没出现、出现几次,简单但会把「的」「是」这种高频词权重抬得很高。TF-IDF 在此基础上乘了一个逆文档频率,越常见的词权重越低,越能体现某条评论特色的词权重越高。对于电商评论这种短文本,TF-IDF 通常比纯词袋效果好,因为它能压住通用词。
from sklearn.feature_extraction.text import TfidfVectorizer # 初始化 TF-IDF,限制最大特征数,避免维度爆炸 tfidf = TfidfVectorizer(max_features=5000, ngram_range=(1, 2), min_df=2) # 在分词结果上拟合和转换 X = tfidf.fit_transform(df['cut_comment']) y = df['label'].values print('特征矩阵形状:', X.shape)参数逐个说:max_features=5000表示只保留权重最高的 5000 个词或词组,防止特征维度上万导致训练慢;ngram_range=(1, 2)表示同时考虑单个词和相邻两个词的组合,比如「不 好」这种二元组能捕捉否定;min_df=2表示至少在 2 条评论里出现过的词才保留,过滤掉只出现一次的噪声词。这三个参数没有绝对标准,数据量大可以调高 max_features,数据量小就调低。
4.2 朴素贝叶斯、SVM 和逻辑回归的对比
选模型时,课程大作业常见的选择是朴素贝叶斯、支持向量机和逻辑回归。朴素贝叶斯训练快、对小数据友好,但假设特征独立,实际文本里词和词有关联,所以效果一般。SVM 在文本分类里表现稳定,尤其线性核,但数据量大时训练慢。逻辑回归可解释性好,能输出概率,调参也直观。我一般会先跑一个逻辑回归做基线,再对比 SVM。
from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression from sklearn.svm import LinearSVC from sklearn.naive_bayes import MultinomialNB from sklearn.metrics import classification_report, accuracy_score # 划分训练集和测试集,stratify 保证正负比例一致 X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42, stratify=y ) # 逻辑回归 lr = LogisticRegression(max_iter=1000, C=1.0) lr.fit(X_train, y_train) lr_pred = lr.predict(X_test) print('逻辑回归准确率:', accuracy_score(y_test, lr_pred)) print(classification_report(y_test, lr_pred)) # 线性 SVM svm = LinearSVC(C=1.0) svm.fit(X_train, y_train) svm_pred = svm.predict(X_test) print('SVM 准确率:', accuracy_score(y_test, svm_pred)) # 朴素贝叶斯 nb = MultinomialNB(alpha=1.0) nb.fit(X_train, y_train) nb_pred = nb.predict(X_test) print('朴素贝叶斯准确率:', accuracy_score(y_test, nb_pred))stratify=y很关键,它保证训练集和测试集里正面负面的比例和原始数据一致,否则可能测试集里全是正面,评估失真。max_iter=1000是逻辑回归的迭代上限,默认值在数据量大时容易不收敛。C是正则化强度的倒数,C 越大越容易过拟合,C 越小越保守。alpha是朴素贝叶斯的平滑系数,防止某个词没出现过导致概率为零。
评估时不要只看准确率。如果正负样本不均衡,要看精确率、召回率和 F1。比如负面评论识别不出来,召回率就低,这时候要调整类别权重或者做重采样。
提示:
classification_report里的 macro avg 和 weighted avg 要分清,样本不均衡时看 weighted avg 更真实。
5. 避坑与排查:那些让准确率虚高或直接报错的细节
5.1 准确率 99% 但模型没用:标签泄漏
现象:训练完准确率接近 100%,换一批新评论预测全错。原因:清洗或分词时不小心把标签信息带进了特征。比如原始数据里有一列「评价等级」,你把它当成文本拼进了评论,模型直接学到了「好评」两个字。解决:特征列只能来自评论文本本身,标签列在训练前必须单独拿出来,不能出现在cut_comment里。
5.2 否定词被停用词表误删
现象:模型把「不好」「不满意」都预测成正面。原因:停用词表里包含了「不」「没」「别」等否定词,分词后「不好」变成「好」。解决:检查停用词表,把否定词和程度副词全部移除;或者用 ngram_range=(1,2) 让「不 好」作为一个特征进入模型。
5.3 中文编码报错 UnicodeDecodeError
现象:pd.read_csv时报错,提示无法解码某个字节。原因:CSV 文件编码不是 utf-8,可能是 gbk 或 gb18030。解决:先试encoding='gbk',再试encoding='gb18030',还不行就用chardet检测编码。不要用errors='ignore'硬吞,会丢字。
5.4 特征维度爆炸导致内存不足
现象:训练时内存飙升,程序被系统杀掉。原因:max_features没设或者设得太大,加上 ngram_range 到 3,特征数轻松上百万。解决:把max_features控制在 5000 到 20000 之间,ngram_range先用 (1,2),数据量不大时不要上 (1,3)。
5.5 测试集和训练集分布不一致
现象:交叉验证分数很高,但实际业务数据上效果差。原因:训练数据来自某个品类,测试数据来自另一个品类,用词习惯完全不同。解决:划分数据时按时间或品类分层,确保训练集和测试集覆盖相似分布;如果做不到,至少用stratify保证标签比例一致。
6. 进阶技巧:用交叉验证和错误分析把模型再推一步
6.1 交叉验证替代单次划分
单次train_test_split的结果受随机种子影响很大,换一个random_state准确率可能差好几个点。更稳的做法是 K 折交叉验证,把数据分成 K 份,轮流做验证集,最后取平均。这样得到的分数更能反映模型的真实水平。
from sklearn.model_selection import cross_val_score from sklearn.pipeline import Pipeline # 把 TF-IDF 和分类器串成管道,避免每次手动转换 pipeline = Pipeline([ ('tfidf', TfidfVectorizer(max_features=5000, ngram_range=(1, 2), min_df=2)), ('clf', LogisticRegression(max_iter=1000, C=1.0)) ]) # 5 折交叉验证,scoring 用 f1 更适合不均衡数据 scores = cross_val_score(pipeline, df['cut_comment'], y, cv=5, scoring='f1') print('每折 F1:', scores) print('平均 F1:', scores.mean())用 Pipeline 的好处是,TF-IDF 的拟合只在训练折上进行,不会把验证折的信息泄漏进去。如果你手动先对整个数据做fit_transform再交叉验证,验证折的词表已经见过测试数据,分数会虚高。scoring='f1'比默认的 accuracy 更适合情感分析,因为负面样本往往更少,F1 能同时看精确率和召回率。
6.2 看混淆矩阵和错分样本
准确率只是一个数字,真正要改进模型,得看它错在哪。混淆矩阵能告诉你正面被错分成负面的有多少、负面被错分成正面的有多少。然后把这些错分样本打印出来,人工读一读,往往能发现新的清洗规则或特征。
from sklearn.metrics import confusion_matrix # 用之前训练好的逻辑回归在测试集上预测 cm = confusion_matrix(y_test, lr_pred) print('混淆矩阵:') print(cm) # 找出预测错误的样本 errors = df.iloc[y_test.index][lr_pred != y_test] print('错分样本数量:', len(errors)) print(errors[['comment', 'label']].head(20))读错分样本时重点关注三类:一是反讽,比如「质量真好,用一天就坏了」,字面正面实际负面;二是中性评论被强行分类,比如「收到货了」,没有情感倾向;三是长评论里情感混合,前半段夸后半段骂。针对反讽,可以加规则或引入更强模型;针对中性,可以考虑三分类而不是二分类;针对混合情感,可以按句子拆分再聚合。
6.3 一个具体技巧:把否定词和程度副词做成特征
除了依赖 ngram,还可以手动构造特征。比如统计每条评论里否定词的数量、程度副词的数量,作为额外特征拼到 TF-IDF 矩阵后面。这个技巧在课程大作业里很加分,因为它体现了对中文情感的理解,而不是单纯调包。
import scipy.sparse as sp import numpy as np neg_words = ['不', '没', '别', '无', '非', '莫'] degree_words = ['很', '太', '非常', '特别', '极其', '十分'] def count_feature(text, word_list): return sum(1 for w in word_list if w in text) df['neg_count'] = df['clean_comment'].apply(lambda x: count_feature(x, neg_words)) df['degree_count'] = df['clean_comment'].apply(lambda x: count_feature(x, degree_words)) # 把两个计数特征转成稀疏矩阵,和 TF-IDF 拼接 extra = sp.csr_matrix(df[['neg_count', 'degree_count']].values) X_combined = sp.hstack([X, extra]) print('拼接后特征形状:', X_combined.shape)sp.hstack是稀疏矩阵的水平拼接,因为 TF-IDF 矩阵本身是稀疏的,用 dense 拼接会撑爆内存。拼完之后重新跑一遍交叉验证,对比 F1 有没有提升。如果没有提升,说明这两个特征和 ngram 信息重复了,可以去掉。这种「加特征、验证、再决定」的习惯,比盲目调参有用得多。
我自己做这类项目最大的教训是:不要一上来就换模型、调参数,先把数据清洗和错分样本读一遍。十次里有八次,问题出在停用词表、编码或者标签泄漏上,而不是模型不够强。把 Pipeline 搭好、交叉验证跑通、错分样本看明白,这份课程大作业就已经超过大多数只贴代码不解释的版本了。希望帮到你。
本文还有配套的精品资源,点击获取