简介这份资源面向Python数据挖掘与自然语言处理初学者围绕豆瓣《肖申克的救赎》影评文本演示如何调用SnowNLP库完成情感分析并配合词云与中文分词流程帮助读者理解从原始评论到情感倾向判定的完整思路。压缩包共10个文件以8个py脚本为主覆盖数据读取、分词处理、SnowNLP多版本调用等环节另含1个csv评论数据集与1个txt文本整体约37KB轻量便于本地运行调试。目前已有16948人学习下载说明该案例在入门教学中具有较高参考价值。读者可借助脚本对照理解情感分析的基本流程掌握SnowNLP的调用方式与结果解读方法并在此基础上迁移到其他评论语料完成分词、情感打分与词云可视化的组合练习适合作为课程实验或自学练手素材。1. 从一堆短评里挖出情绪这个项目到底在做什么假设你手里有一份从某影视社区抓下来的评论数据几千条短评混在一起有夸的、有骂的、有阴阳怪气的靠人眼一条条看根本不现实。这个项目就是冲着这个场景来的用 Python 把评论读进来调 SnowNLP 给每条评论打一个 0 到 1 之间的情感分再按分数切成正面、中性、负面三档最后用词云把高频词可视化出来。它适合两类人——刚学完 Python 基础、想找一个完整小项目练手的同学以及需要快速给一批中文短文本做情绪摸底的数据分析初学者。整条链路不依赖深度学习框架一台普通笔记本就能跑完属于典型的“轻量级中文情感分析”落地案例。2. 技术选型与项目骨架为什么是 SnowNLP 而不是 BERT2.1 选型逻辑轻量、开箱即用、中文友好做中文情感分析摆在面前的路其实有好几条。一条是上预训练模型比如 BERT 系列效果好但门槛高——要装 PyTorch 或 TensorFlow要下几百兆的权重文件推理还得有 GPU 才跑得舒服。另一条是用 SnowNLP它自带一个已经训练好的中文情感模型pip install snownlp一行装完SnowNLP(text).sentiments一行出分对新手极其友好。这个项目选 SnowNLP 的核心理由就三个字跑得动。它的情感分是 0 到 1 的连续值越接近 1 越正面越接近 0 越负面。对于影视评论这种口语化、短句为主的文本SnowNLP 的准确率虽然比不上大模型但做趋势性判断完全够用。而且它不依赖网络请求装完就是本地推理没有 API 调用次数限制也没有密钥配置的麻烦。常见做法是先用 SnowNLP 快速跑一版基线结果看看数据分布长什么样再决定要不要上更重的模型。这个项目就是基线版本适合作为整个分析流程的第一步。2.2 目录结构一个能直接跑的小工程长什么样一个合格的项目骨架不需要多复杂但得让人一眼看懂哪个文件干什么。我一般会这样组织sentiment_douban/ ├── data/ │ ├── comments.csv # 原始评论数据 │ └── stopwords.txt # 中文停用词表 ├── output/ │ ├── sentiment_result.csv # 带情感分的输出 │ └── wordcloud.png # 词云图 ├── src/ │ ├── preprocess.py # 数据清洗与分词 │ ├── analyze.py # 情感分析主逻辑 │ └── visualize.py # 词云生成 ├── requirements.txt └── main.py # 入口脚本data/放原始数据和停用词output/放结果src/放三个核心模块main.py串起整条流水线。这种分法好处是每个模块职责单一你想单独调词云就只跑visualize.py不用每次都把情感分析重跑一遍。2.3 依赖清单与版本注意requirements.txt里需要写清楚snownlp0.12.3 jieba0.42.1 wordcloud1.9.2 matplotlib3.7.1 pandas2.0.3这里有个血泪经验wordcloud在 Windows 上安装时经常因为缺少 C 编译环境而翻车。解决办法是去下载对应的.whl文件本地安装或者直接用conda install -c conda-forge wordcloud。另外matplotlib在无图形界面的服务器上跑会报错需要在代码里加matplotlib.use(Agg)切换到非交互后端。注意SnowNLP 自带的情感模型对繁体中文和网络新词的支持有限如果你的评论数据里大量出现拼音缩写或谐音梗需要先在预处理阶段做一轮替换。3. 核心模块拆解从原始评论到情感分数的完整链路3.1 数据预处理清洗、去重、分词原始评论数据通常很脏——有 HTML 标签残留、有纯表情符号、有重复刷屏的内容。预处理这一步不做干净后面的情感分会被严重干扰。import re import pandas as pd import jieba def clean_text(text): 清洗单条评论去标签、去特殊符号、去多余空白 if not isinstance(text, str): return # 去掉 HTML 标签 text re.sub(r.*?, , text) # 只保留中文、英文、数字和基本标点 text re.sub(r[^\u4e00-\u9fa5a-zA-Z0-9。、], , text) # 合并连续空白 text re.sub(r\s, , text).strip() return text def load_and_clean(filepath): 读取 CSV 并完成清洗去重 df pd.read_csv(filepath) df[clean_comment] df[comment].apply(clean_text) # 去掉空评论和重复评论 df df[df[clean_comment].str.len() 2] df df.drop_duplicates(subsetclean_comment) return df def segment(text, stopwords): jieba 分词并过滤停用词 words jieba.lcut(text) return [w for w in words if w not in stopwords and len(w) 1]clean_text里的正则[^\u4e00-\u9fa5a-zA-Z0-9。、]是关键——它把表情符号、特殊字符全部干掉只留下对情感判断有用的内容。load_and_clean里过滤掉长度小于等于 2 的评论是因为太短的文本比如“好看”“烂”虽然情感明确但分词后几乎没有有效词汇放在词云里也没意义。segment函数用 jieba 分词后过滤停用词和单字单字过滤是因为“的”“了”“是”这类词对情感分析没有贡献。停用词表我一般会准备一份基础版包含“的、了、是、在、我、你、他、她、它、这、那、就、都、也、还、又、很、非常”等常见虚词再加上影视评论场景特有的“电影、电视剧、剧情、演员、导演”这类中性名词——它们在词云里会占据大片面积但并不能反映情绪。3.2 情感打分SnowNLP 的调用与分档策略预处理完成后核心逻辑就一行代码的事但分档策略需要想清楚。from snownlp import SnowNLP def get_sentiment_score(text): 返回 0-1 之间的情感分越接近 1 越正面 if not text or len(text) 2: return None try: s SnowNLP(text) return s.sentiments except Exception as e: print(f分析失败: {text[:20]}... 错误: {e}) return None def classify(score): 按分数分档正面 / 中性 / 负面 if score is None: return 未知 if score 0.6: return 正面 elif score 0.4: return 负面 else: return 中性 def batch_analyze(df): 批量分析并统计分布 df[sentiment_score] df[clean_comment].apply(get_sentiment_score) df[sentiment_label] df[sentiment_score].apply(classify) print(df[sentiment_label].value_counts()) return dfget_sentiment_score里加了 try-except是因为 SnowNLP 在处理极短文本或纯数字文本时偶尔会抛异常不捕获的话整个批量任务会中断。分档阈值 0.6 和 0.4 是经验值——SnowNLP 的分数分布通常集中在 0.3 到 0.8 之间两端极端值较少用 0.6/0.4 做切分能让三档分布相对均衡。如果你发现中性档占比过高可以调整到 0.55/0.45让更多评论被归入正面或负面。batch_analyze里用value_counts()打印分布这一步很重要——如果正面评论占比超过 90%要么是数据本身有问题比如只抓了好评要么是阈值设得太松需要回头检查。3.3 词云生成让高频词自己说话情感分告诉你“整体情绪怎么样”词云告诉你“大家在说什么”。两者结合才能形成完整判断。from wordcloud import WordCloud import matplotlib matplotlib.use(Agg) # 无图形界面服务器必须加这行 import matplotlib.pyplot as plt from collections import Counter def build_wordcloud(df, stopwords, output_path): 基于正面评论生成词云 # 只取正面评论做词云负面评论可以单独生成一张 positive df[df[sentiment_label] 正面] all_words [] for text in positive[clean_comment]: all_words.extend(segment(text, stopwords)) freq Counter(all_words) # 过滤低频词避免词云太杂乱 freq {w: c for w, c in freq.items() if c 3} wc WordCloud( font_pathsimhei.ttf, # 中文字体路径必须指定 width1200, height800, background_colorwhite, max_words150, colormapviridis ) wc.generate_from_frequencies(freq) plt.figure(figsize(12, 8)) plt.imshow(wc, interpolationbilinear) plt.axis(off) plt.savefig(output_path, dpi150, bbox_inchestight) plt.close()font_path是中文词云最容易翻车的地方——不指定中文字体生成的图片全是方块。Windows 下可以用C:/Windows/Fonts/simhei.ttfLinux 下需要把字体文件放到项目目录里并写相对路径。freq过滤掉出现次数小于 3 的词是为了让词云只展示真正有代表性的高频词否则长尾词会挤占版面。colormapviridis是配色方案换成Reds或Blues也可以看个人审美。提示正面和负面评论建议分别生成两张词云对比看。正面词云里出现“演技、剧情、节奏”说明观众关注内容本身负面词云里出现“尴尬、拖沓、逻辑”则直接指向差评原因对比起来信息量翻倍。4. 跑起来从零到出图的完整操作步骤4.1 环境准备与数据格式先把 Python 环境准备好建议用 3.8 以上版本。虚拟环境不是必须的但强烈建议——SnowNLP 和 wordcloud 的依赖有时候会跟系统里其他包打架。python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install -r requirements.txt数据文件comments.csv至少需要一列comment里面放评论文本。如果你是从网页抓的数据可能还带有user、date、rating等列不影响load_and_clean只取comment列。数据量建议在 500 到 5000 条之间——太少统计意义不强太多 SnowNLP 跑起来会慢单条大约 1 到 3 毫秒5000 条大概 10 秒左右。4.2 主流程串联与运行main.py把三个模块串起来from src.preprocess import load_and_clean, segment from src.analyze import batch_analyze from src.visualize import build_wordcloud def load_stopwords(path): with open(path, r, encodingutf-8) as f: return set(line.strip() for line in f if line.strip()) if __name__ __main__: stopwords load_stopwords(data/stopwords.txt) df load_and_clean(data/comments.csv) print(f清洗后剩余 {len(df)} 条评论) df batch_analyze(df) df.to_csv(output/sentiment_result.csv, indexFalse, encodingutf-8-sig) build_wordcloud(df, stopwords, output/wordcloud.png) print(完成结果已输出到 output/ 目录)运行python main.py控制台会先打印清洗后的评论条数和三档情感分布然后在output/下生成sentiment_result.csv和wordcloud.png。encodingutf-8-sig是为了让 Excel 打开 CSV 时不乱码这个小细节很多人会忽略。4.3 结果解读分数分布说明什么跑完之后重点看两个东西。第一是value_counts()的输出——如果正面占比在 50% 到 70% 之间说明数据分布比较健康如果负面占比异常高可能是抓取时带了偏见比如只抓了差评区。第二是词云图——正面词云和负面词云各生成一张对比看哪些词只出现在一边。常见做法是再算一个平均情感分df[sentiment_score].mean()。这个值在 0.5 以上说明整体偏正面0.5 以下偏负面。但要注意平均分会被极端值拉偏所以最好同时看中位数median()。5. 避坑与排查那些让我重跑三遍的坑5.1 词云全是方块现象生成的wordcloud.png里所有中文都显示成方框或乱码。原因WordCloud默认字体不支持中文没有指定font_path或指定的路径不对。解决确认字体文件存在且路径正确。Windows 用C:/Windows/Fonts/simhei.ttfLinux 把simhei.ttf复制到项目目录下写font_pathsimhei.ttf。如果还是不行换msyh.ttf微软雅黑试试。5.2 SnowNLP 分数全部集中在 0.5 附近现象几千条评论的情感分几乎都在 0.45 到 0.55 之间分不出正面负面。原因SnowNLP 的模型对短文本和口语化表达不敏感尤其是“还行”“一般”“凑合”这类中性词模型给的分就是 0.5 左右。解决调整分档阈值把正面调到 0.55 以上、负面调到 0.45 以下让更多评论被区分开。或者对文本做增强——把“不”和后面的词合并成一个 token避免“不好”被拆成“不”和“好”分别处理。5.3 分词结果里全是单字现象词云里出现大量“的”“了”“是”这种单字有效词很少。原因停用词表没加载成功或者segment函数里的len(w) 1条件没生效。解决检查stopwords.txt的编码是不是 UTF-8以及load_stopwords有没有正确返回 set。另外确认 jieba 分词前没有对文本做过度清洗——如果把标点全删了jieba 的切分准确率会下降。5.4 批量分析跑到一半报错中断现象batch_analyze跑到几百条时抛出异常整个程序退出。原因某条评论触发了 SnowNLP 的内部错误常见于纯数字、纯英文或超长文本。解决get_sentiment_score里已经加了 try-except但如果异常发生在SnowNLP(text)初始化阶段需要在调用前先做长度和内容检查。我一般会加一句if len(text) 500: text text[:500]避免超长文本拖慢速度或触发异常。5.5 输出 CSV 用 Excel 打开乱码现象sentiment_result.csv在 Excel 里打开全是乱码。原因Excel 默认用 GBK 解码而文件是 UTF-8 编码。解决to_csv时加encodingutf-8-sig这个编码会在文件开头写入 BOM 标记Excel 能正确识别。6. 二次开发从基线版本到能打的分析工具这个项目跑通之后最自然的改造方向是换模型。SnowNLP 的准确率有限如果你手头有标注数据可以把它替换成transformers里的中文情感分类模型比如uer/roberta-base-finetuned-jd-binary-chinese或bert-base-chinese微调版本。替换方式很简单——把get_sentiment_score里的SnowNLP(text).sentiments换成模型推理的softmax输出分档逻辑完全不用动。第二个方向是加维度。现在只有情感分一个维度你可以再加一个“主题分类”——用 jieba 分词后统计高频名词把评论自动归到“演技”“剧情”“特效”“配乐”几个桶里然后交叉分析“哪个主题的负面情绪最集中”。这个改造只需要在analyze.py里加一个classify_topic函数用关键词匹配就能实现不需要额外训练模型。第三个方向是做对比。如果你有两部剧的评论数据可以分别跑一遍然后对比情感分布和词云差异。我一般会写一个compare.py把两组数据的value_counts()并排打印再把两张词云拼成一张对比图。这个改造对代码改动最小但产出的分析价值最高。最后一个技巧是关于阈值调优的。不要死守 0.6/0.4而是先跑一遍全量数据用df[sentiment_score].describe()看分位数然后按 25% 和 75% 分位点来切分。这样能保证三档分布均衡避免某一档样本过少导致统计不可靠。从那以后我每次做情感分析项目都强制先跑一遍describe()看分布再决定阈值——这个习惯帮我省掉了至少三次“结果看起来不对劲但不知道哪里错”的排查时间。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?