豆瓣电影评论情感分析与词云源码全解析,附避坑指南

📅 发布时间:2026/10/12 18:43:29
豆瓣电影评论情感分析与词云源码全解析,附避坑指南
简介基于Python的豆瓣电影评论情感分析与关键词提取WordCloud设计源码面向希望从影评中挖掘情感倾向与话题焦点的开发者、研究人员。项目实现文本预处理、去停用词、情感分类、TF-IDF关键词提取及词云可视化流程配合多部影片实例便于理解NLP与分析结果的对应关系。压缩包共39个文件、约44.31MB含19个PNG图表、6个xlsx分析报告、4个xml配置、4个txt辅助文本、2个otf字体和main.py源码等图表涵盖唐探1900、哪吒之魔童闹海、射雕英雄传侠之大者等影片的词云、情感分布与趋势图。还附带停用词表和过滤文本方便替换语料直接运行。已有183人学习适合需要参考完整工程结构、复用词云模板或快速上手评论情感分析的读者。1. 这一份豆瓣电影评论情感分析与词云源码值不值得先跑一遍春节档六部电影唐探1900、哪吒之魔童闹海、熊出没·重启未来、蛟龙行动、射雕英雄传侠之大者、封神第二部战火西岐的豆瓣评论如果还靠人工一条条翻那你会发现翻了半个小时还没看完第一屏。这里有个基于Python的豆瓣电影评论情感分析与关键词提取wordcloud设计源码把爬下来或导出的评论喂给main.py就能直接出情感分布图、评论趋势图、词云图以及一份xlsx分析报告。适合正在做舆情分析作业、准备写影评数据报告、或者想用NLP给电影宣发做参考的人。它算不上大工程但作为一条完整可复现的NLP流水线比东拼西凑的脚本要省事得多。这篇笔记我把源码包里的文件、参数、坑都拆开讲。2. 源码包结构38个文件里藏着一条完整的NLP流水线拿到压缩包不要急着运行先把文件分三类看明白。第一类是脚本与配置包括main.py、stopwords.txt、filterText.txt、userdict.txt第二类是字体与输出模板包括SourceHanSansCN.otf、NotoSansCJKMedium.otf、font_test.png第三类是六部电影各自的输出每个电影都有分析报告xlsx、趋势图png、情感分布png、词云png。还有.gitignore、.idea等IDE与Git相关文件这些不影响运行但说明作者用PyCharm开发并且纳入了版本管理。2.1 main.py不是单脚本而是一条流水线main.py是项目主体它做的事情不是简单的“读取-输出”而是依次执行读取评论数据、文本清洗、分词、去停用词、过滤无用文本、情感打分、关键词提取、生成图表和词云、写出xlsx报告。常见做法是把每一步写成函数主流程用ifname main:驱动。如果你在PyCharm里打开项目直接运行main.py要留意开头的数据路径变量因为代码默认处理哪部电影、数据文件放在哪个目录都在这个变量里控制。源码包里六部电影的输出文件都齐了说明作者至少完整跑通过一遍流程不是半成品。这对我们来说是个好消息环境配置对了就能复现不需要再猜数据格式。我一般会先备份原始main.py然后在副本上改参数这样随时可以对比源码默认行为和自己的改动。2.2 支撑文件的作用filterText、stopwords、userdict、两个otf字体stopwords.txt是停用词表用于过滤“的、了、就是、其实”这类无意义词filterText.txt可能存放需要过滤的正则或特定文本碎片比如无意义的字符组合userdict.txt是用户词典用来保证“哪吒”“魔童闹海”“唐探”这样的词不会被错误切分。两个otf字体文件是给wordcloud用的中文字体如果没有指定生成的词云全是方块。SourceHanSansCN.otf思源黑体和NotoSansCJKMedium.otf都可以用后者字符集更完整。这三个配置文件改起来没什么门槛但影响极大。我接手这类项目的第一件事就是把stopwords.txt打开扫一遍看它有没有过滤掉“特效”“演技”这种对电影评论有区分度的词。如果停用词表太激进情感分析的关键词会变得很干瘪词云也只剩“电影”“剧情”这类通用词。2.3 输出文件命名规则从报告xlsx到趋势图、情感分布、词云看文件名就能猜到代码的产物命名规则{电影名}_分析报告.xlsx、{电影名}_趋势图.png、{电影名}_情感分布.png、{电影名}_词云.png。xlsx里一般包括评论明细、情感得分、关键词列表、统计汇总。趋势图是评论数量或情感均值随时间的变化情感分布图是正面/负面/中性占比。这个命名规则提示我作者在代码里应该用了一个电影名列表循环生成而不是每个电影写一遍。文件类型数量用途main.py1主流程脚本stopwords.txt1停用词表filterText.txt1过滤规则/文本userdict.txt1用户词典*.otf2词云中文显示字体*.png19词云/分布/趋势图*.xlsx6分析报告*.xml / .gitignore多个IDE/版本控制如果你只想跑一部电影把电影列表改成单个元素即可输出也不会被其他电影覆盖。注意xlsx文件名里的电影名带全角冒号在Windows下虽然合法但某些旧版Excel可能打不开后面避坑章节会讲。3. 情感分析这块先跑通默认模型再决定要不要换算法很多人在拿到源码后直接跑结果出来的情感分布跟自己体感差很多于是怀疑脚本有bug。其实情感分析本身就是个概率问题不是非黑即白。这套源码的情感分析大概率走的是“词典打分 规则修正”路线而不是训练一个深度模型。理由很现实模型训练需要大量标注数据而词典方法一两百行代码就能出结果对电影评论这种短文本也够用。3.1 情感分析的基本路线词典打分还是模型分类常见做法有两种。第一种是情感词典法把评论分词后逐个词去匹配情感词典正面词加分、负面词减分最后总分大于阈值判为正向小于阈值判为负向其余中性。第二种是用scikit-learn训练分类模型先TF-IDF向量化再用朴素贝叶斯或逻辑回归。这套源码的主脚本如果是走词典路线你会发现它自带情感词典表或者通过filterText来修饰分数。我在实际项目里电影评论领域用词典法反而比通用模型更稳定。电影评论有大量口语化表达、反讽和烂梗通用模型容易把“特效炸了”判成负面词典法配合人工调规则反而更可控。但缺点也很明显词典覆盖不全遇到网络新词容易漏判。所以第一步先跑通默认版本拿到一份结果再用抽样人工标注校验比一上来就重复造轮子强。3.2 数据预处理去停用词、清洗、用户词典情感分析前必须清洗原始评论。常见的清洗步骤包括去HTML标签、去URL、去用户、去多余换行、去emoji或转换为描述、统一繁体简体。过滤规则写在filterText.txt里你可以把它理解为一条正则列表凡是匹配到的文本碎片直接剔除。stopwords.txt负责去掉无情感色彩的词。而userdict.txt里的词会在jieba分词时被强制保留为一个整体避免“魔童”“闹海”被切成“魔”“童”“闹”“海”。import jieba import re def clean_text(text): # 去掉URL、、多余空白按需扩展 text re.sub(rhttp\S, , text) text re.sub(r\w, , text) text re.sub(r\s, , text) return text.strip() # 自定义词典保证电影名、角色名不被错切 jieba.load_userdict(userdict.txt)这里load_userdict会在分词时把用户词视为整体。注意userdict.txt每行一个词可以用空格或Tab分隔词频、词性比如“哪吒 10 n”。freq给得越大新词越容易被识别但也不要无限大否则会影响正常切分。如果你发现某些评论里“哪吒”还是被切成“哪”“吒”就把词频调大再重新运行。3.3 跑一次情感分析并输出分布图和xlsx报告主流程里大概率有类似下面的逻辑读评论 - 预处理 - 逐条打分 - 统计标签 - 写xlsx - 画分布图。如果你只想看某个电影的结果可以直接修改main.py里的电影列表movies [哪吒之魔童闹海] # 完整流程函数假设在同一个模块里 for movie in movies: comments load_comments(movie) scores [sentiment_score(c) for c in comments] labels classify(scores, pos_threshold0.1, neg_threshold-0.1) save_report(movie, comments, scores, labels) plot_sentiment_dist(movie, labels) plot_trend(movie, scores)参数说明pos_threshold和neg_threshold决定什么分数算正面、什么算负面。默认0.1和-0.1意味着接近中性的分数会被归为中性。这个阈值你可以根据自己的数据分布调整如果正面评论明显过多调高pos_threshold如果负面刷屏把neg_threshold往下压。load_comments返回的是评论列表每一条最好保留发布时间和评分字段这样趋势图才画得出来。3.4 调整情感阈值或标签让结果更贴合你的判断如果源码输出里没有阈值参数那分数计算可能用的就是一个固定分段score大于0为正score小于0为负其余中性。这时候你会发现很多“还行”“一般”都被算成中性导致中性占大头。我给这类脚本加过一个小改动把得分绝对值小于0.05的评论单独抽出来打标为疑似中性然后人工抽查几百条用结果反向校准阈值。情感分析这玩意儿多少带点玄学不同电影类型阈值都不一样。喜剧片容易高分组团文艺片评论两极分化一个阈值套所有电影必然不准。所以我总是把阈值做成配置文件里的变量而不是硬编码在函数里这样每个电影可以单独调。4. 关键词提取与词云TF-IDF / TextRank 和字体这个大坑词云图是这套源码最有视觉效果的部分但也是最容易出问题的地方。关键词提取直接决定词云内容字体决定中文能不能正常显示。这两步我拆开讲每一步都可能让成品变成一张废图。4.1 关键词提取词频、TF-IDF、TextRank怎么选三种方式各有适用场景。词频统计简单粗暴但每部电影都出现的“电影”“剧情”“演员”会被排到前面没有区分度。TF-IDF能压低普遍词的权重突出这部电影相对独特的词。TextRank则通过词共现网络给关键词排权重适合长文本短评论上效果反而不如TF-IDF。这套源码如果用的是jieba内置的jieba.analyse.extract_tags那默认就是TF-IDF算法你可以传topK参数控制返回多少个词。import jieba.analyse top_words jieba.analyse.extract_tags( text, # 已清洗的全文 topK50, # 提取前50个关键词 withWeightTrue, # 返回权重词云绘制时需要 allowPOS(n, v, a) # 只保留名词、动词、形容词 )allowPOS这个参数很关键默认会全词性输出结果经常混进一堆副词和连词。我一般只用名词加形容词动词参与度不高词云里的词才“像人话”。如果你想要更严格的对比可以把六部电影的文本合并后单独提取一批全局停用词再对每部电影提取关键词看到的东西会干净很多。4.2 生成词云前必须做的三件事分词、去停用词、字体指定如果你自己写词云生成的代码顺序一定要对先分词再过滤停用词最后把文本拼成空格分隔的字符串交给wordcloud。有个常见错误是把整段原始评论直接扔进WordCloud因为WordCloud默认是按空格和标点切词中文没有空格最后产出的图就是一堆乱码或整个文本粘成一团。所以必须用jieba先分词# 所有评论清洗后合并成一个长文本 seg_list [] for comment in comments: words jieba.cut(clean_text(comment)) for w in words: if w not in stop_words and w.strip(): seg_list.append(w) space_text .join(seg_list)stop_words从stopwords.txt加载用set类型存判断效率高。注意滤掉单字和纯标点否则词云里全是“的”“了”“好”。userdict.txt确保专有名词不被切碎不然“唐探1900”会变成“唐探”和“1900”词云里会出现数字看起来很业余。4.3 用 wordcloud 生成中文词云参数设置与代码中文环境下必须指定字体路径否则WordCloud找不到中文字形输出全是方块。源码包里自带的SourceHanSansCN.otf就是为了这里。我一般用以下参数from wordcloud import WordCloud wc WordCloud( font_pathSourceHanSansCN.otf, # 中文必须 width1200, height800, max_words100, background_colorwhite, collocationsFalse # 避免重复词组堆叠 ) wc.generate_from_frequencies(dict(top_words)) # 用关键词权重生成 wc.to_file(f{movie}_词云.png)width和height决定画布大小输出png默认是位图分辨率够用就行不要盲目设太大否则内存占用高且生成速度慢。max_words控制在100左右词太多会糊成一片。collocationsFalse是为了让WordCloud不要自动把相邻词拼接成“电影 剧情”这类词组否则关键词权重会被稀释。4.4 从词云反推评论热点词云图不只是好看它可以用来快速验证情感分析结果。比如哪吒之魔童闹海词云里如果“好看”“特效”“燃”大字号出现正向情感占比高就说得通如果负面词字号很大但情感分布显示正向高那就要回头检查停用词或阈值了。实际动手时我会把xlsx报告里的关键词列表和词云图对照看确认词云没有过滤掉关键负面词。还有一个容易被忽视的点词云生成的随机颜色和布局每次都不一样但只要词和权重不变信息量就稳定。如果你看到同一批数据两次生成的词云差别巨大那是wordcloud的随机性不用慌。要复现结果可以在生成前设置random_state参数虽然wordcloud没有直接暴露但你可以固定seed稍麻烦我一般留给有强迫症的人。5. 避坑与常见问题中文乱码、零词频、字体缺失、报告打不开这类源码包在别人电脑上跑不起来八成倒在下面几个坑上。我把踩过的记录按“现象-原因-解决”写出来基本覆盖了新用户能遇到的主要问题。5.1 词云输出全是一排排方块字现象png文件生成了但上面不是汉字是方框或乱码。原因WordCloud没有指定font_path或者指定的字体文件路径不存在。Windows下默认字体没有中文字形Linux下也一样。解决确认源码里的字体文件名和路径一致。如果还是不行直接用绝对路径wc WordCloud(font_pathrD:\projects\movie_wordcloud\SourceHanSansCN.otf, ...)我建议先把font_test.png跑出来那应该是一个字体渲染测试图能正常显示就说明字体路径没问题。如果font_test.png本身就是乱码那就重新设置字体路径别急着跑主流程。5.2 关键词提取结果为空或者全是“我们”“电影”现象extract_tags返回空列表或者返回的全是停用词。原因文本清洗后剩的字太少或者stopwords.txt包含的词太多另一个原因是jieba.analyse需要全文足够长评论只有几条撑不起统计。解决检查load_comments是不是读到了空数据打印前100条评论长度。通常累计文本少于500字时TF-IDF的统计没有意义可以把多部电影评论合并后再提取关键词或者调低topK试试。我跑过一个只有80条评论的冷门电影topK50提取出来的全是单字改成topK20才正常。5.3 输出xlsx打不开或提示格式损坏现象Excel打开报告时提示文件损坏或者只看到第一行表头。原因多数是pandas或openpyxl在写入多sheet时异常中断也可能是文件名里有非法字符比如“”在Windows下是合法的但某些版本Excel对全角冒号敏感。解决把项目路径改为纯英文目录电影名里带“”的在变量里替换成“_”。我一般这样写safe_name movie.replace(, _) report_name f{safe_name}_分析报告.xlsx使用pandas的ExcelWriter时记得把engine设为openpyxl写完调用report.save()再关闭。如果你用的还是xlwt那只能写xls别和openpyxl混用。5.4 main.py直接运行后什么都没发生现象控制台没报错但也没看到新的png和xlsx。原因常见是文件路径是相对路径而当前工作目录不在项目根目录下或者main.py里有个ifname main:分支但分支内没有调用主函数。解决在PyCharm里把工作目录设置成项目根目录或者在main.py里用os.chdir(os.path.dirname(file))固定工作目录然后检查主函数是否被调用。这个小坑我能记一辈子因为第一次跑这类源码时浪费了半小时定位最后发现是自己的工作目录在Desktop。5.5 情感分布结果一边倒现象六部电影全部显示正面90%以上或者全部负面。原因情感词典偏向严重或阈值设置太高/太低也可能评论数据源本身有清理问题没去掉水军评论。解决先随机抽50条评论人工标注再计算平均得分。如果平均分明显偏离0考虑调整阈值或补充情感词典。情感分析没有银弹这一步是最需要人工干预的。还有一点如果评论里有大量短评“赞”“顶”正分数会被拉高建议把少于5个字的评论单独过滤掉它们信息量太低。6. 进阶用法把单电影分析改成批量对比并自定义电影列表这套源码已经很接近成品但留了个扩展口电影列表。我拿到后第一件事是把main.py里的movies写成了六个电影名跑通一遍第二件事就是改成从命令行读电影名这样下次想分析别的电影不用改代码。6.1 用命令行参数扩展电影列表在main.py顶部加一段解析接收sys.argv里的参数import sys if len(sys.argv) 1: movies sys.argv[1:] else: movies [哪吒之魔童闹海, 唐探1900]运行方式变成python main.py 流浪地球3 疯狂的外星人命令行传入的电影名会覆盖内置列表。这样你写一个爬虫脚本把多部电影的评论存成统一格式的csv再循环调用这个main.py就能自动生成所有报告不用重复改文件。注意爬取时加延时豆瓣对频繁请求会限制源码虽然没带爬虫但你自己补的时候别把访问密度拉太高。6.2 把六部电影的xlsx报告合成一张对比表我更习惯把六部电影的xlsx报告里的情感占比提取出来拼成一张横向对比图。报告里的sheet名可能叫“统计汇总”也可能是“情感统计”先打开看一眼再写代码import pandas as pd import glob rows [] for f in glob.glob(*_分析报告.xlsx): df pd.read_excel(f, sheet_name统计汇总) rows.append({电影: f.split(_)[0], 正面占比: df[占比][0]}) summary pd.DataFrame(rows) summary.to_excel(春节档情感对比.xlsx, indexFalse)注意如果sheet名或列名不匹配pandas会报错这时先打印df.columns看看实际字段。输出对比表后我通常还会把趋势图全部合并到一张画布上观察六部电影在映后第几天的评论量最高这比单独看单部电影更能看出宣发节奏。最后我会检查一遍词云图、情感分布、趋势图三个文件的时间戳确认都是最新生成的不是上一轮遗留的老图。那个检查习惯帮了我很多次因为脚本有时被中断老图还在兜底看结果时很容易被误导。从那以后我每次跑新数据集都强制先验证“字体路径-停用词表-评论读取行数”三件事再去看图。希望这篇笔记能帮你把这套源码真正跑起来少踩几个我看过的坑祝顺利。本文还有配套的精品资源点击获取