简介这是一套面向高校计算机相关专业学生的Python课程设计资源主题为酒店评论情感分析系统适合作为期末大作业、课程设计或毕业设计的参考范例也便于编程初学者理解文本情感分析的实现原理。压缩包共28个文件约4.42MB包含2个py源码文件、14个txt情感词典与停用词表、1个docx技术文档、1个pptx结题报告、2个rar语料包及若干备份文件源码结构清晰且关键算法配有中文注释。系统集成了数据预处理、特征提取、模型训练与情感分类等完整流程并配有交互界面下载后经简易配置即可运行。目前已有32人学习下载读者可从中获得完整项目源码、情感词典资源、技术文档与演示文稿快速掌握酒店评论文本情感倾向分析的整体实现思路。1. 从一份酒店评论情感分析源码说起它到底能跑出什么结果打开这份基于Python的酒店评论情感分析源码文档.zip第一眼看到的不是某个高大上的深度学习模型而是一堆词典文件posdict.txt、negdict.txt、ishdict.txt、insufficientdict.txt、mostdict.txt、verydict.txt外加四份停用词表。这套组合拳说明它走的是基于情感词典的规则打分路线不是 BERT 微调也不是 LSTM 训练。对课程设计和期末大作业来说这反而是最务实的选择——不需要 GPU不需要标注几万条数据装好 Python 就能跑答辩时还能把打分逻辑一行行讲清楚。它能解决的核心问题很具体给一条酒店评论比如“房间干净但隔音太差前台态度还行”输出一个情感倾向分数并判定为正面、负面或中性。配套的emotion_score.py负责打分run.py负责调度wordcloud.jpg和酒店评论情感分析.pptx说明它还做了词云可视化和答辩演示。适合谁正在找 Python 课程设计题目的本科生、想快速理解文本情感分析完整链路的自学者以及需要一份可讲、可改、可扩展的参考实现的开发者。下面我按实际拆包和复现的顺序把这份资源从环境配置讲到参数调优。2. 环境配置与项目结构把 zip 跑起来需要几步2.1 依赖安装与 Python 版本选择这份源码没有附带requirements.txt这是第一个需要自己补的地方。从代码里用到的库来看核心依赖是jieba做中文分词matplotlib和wordcloud做可视化pandas和numpy做数据处理。Python 版本建议用 3.8 到 3.10太新的版本在某些老库上容易出兼容问题。# 创建虚拟环境避免污染全局包 python -m venv hotel_sentiment_env # Windows 激活 hotel_sentiment_env\Scripts\activate # macOS / Linux 激活 source hotel_sentiment_env/bin/activate # 安装核心依赖 pip install jieba pandas numpy matplotlib wordcloud这里有个细节wordcloud在 Windows 上安装时经常因为缺少 C 编译环境而失败。常见做法是先去下载对应的.whl文件本地安装或者直接用pip install wordcloud --only-binary:all:强制走预编译包。如果只是跑情感打分、暂时不需要词云可以先跳过wordcloud不影响emotion_score.py和run.py的主流程。jieba的安装通常没问题但要注意它首次运行时会构建前缀词典缓存大概需要几秒到十几秒。如果卡在“Building prefix dict”不动不是死机等它跑完就行。后续再运行就会走缓存速度快很多。2.2 目录结构与文件职责解压后的目录里文件可以分成四类理清楚之后改代码就不会迷路类别文件作用入口脚本run.py主调度读取评论、调用打分、输出结果核心算法emotion_score.py分词、词典匹配、情感分数计算情感词典posdict.txt、negdict.txt、mostdict.txt、verydict.txt、ishdict.txt、insufficientdict.txt、inversedict.txt定义正面词、负面词、程度副词、否定词、反义词停用词表htu_stopword.txt、哈工大停用词表.txt、中文停用词库.txt、stopword.txt、四川大学机器智能实验室停用词库.txt过滤无意义词数据与文档neg.rar、pos.rar、酒店评论情感分析.docx、酒店评论情感分析.pptx正负样本评论、技术文档、答辩 PPTneg.rar和pos.rar里应该是正负面评论语料解压后可以用来测试打分效果。README.md和README.md.zbak是说明文件的备份.zbak后缀的文件是原始备份改坏了可以拿回来对照。注意ishdict.txt、inversedict.txt、insufficientdict.txt这几个文件在目录里出现了两次一次带.zbak后缀。带.zbak的是备份代码实际读取的是不带后缀的版本。如果你修改了词典导致结果异常直接用.zbak文件覆盖回去就能恢复。2.3 首次运行与结果验证环境装好后先别急着改代码用原始状态跑一遍确认基线结果。假设run.py的入口逻辑是读取某个评论文件并输出分数典型运行方式# 在项目根目录下运行 python run.py如果run.py需要指定输入文件常见写法是python run.py --input pos.rar解压后的评论.txt --output result.csv具体参数名以run.py里的argparse或sys.argv定义为准。跑完之后重点看两个东西一是控制台有没有报KeyError或UnicodeDecodeError二是输出的情感分数分布是否合理。如果所有评论都被判成中性大概率是词典路径没对上或者分词结果和词典条目没有匹配上。验证方法很简单手动构造三条评论——纯正面“服务很好房间干净整洁”、纯负面“隔音差卫生堪忧不会再住”、混合“位置不错但设施老旧”。跑一遍看分数是否呈现正、负、接近零的分布。如果纯正面和纯负面分数差不多说明否定词或程度副词的处理逻辑有问题需要进emotion_score.py排查。3. 情感打分核心逻辑词典匹配、否定词与程度副词怎么协同3.1 分词与停用词过滤中文情感分析的第一步永远是分词。这份源码用jieba做切分然后用停用词表过滤掉“的”、“了”、“是”这类对情感判断没有贡献的词。停用词表有四份来源不同覆盖范围略有差异。常见做法是把它们合并成一个集合去重后使用。import jieba def load_stopwords(stopword_files): 加载多份停用词表并合并去重 stopwords set() for filepath in stopword_files: with open(filepath, r, encodingutf-8) as f: for line in f: word line.strip() if word: stopwords.add(word) return stopwords # 四份停用词表合并 stopword_files [ stopwords/htu_stopword.txt, stopwords/哈工大停用词表.txt, stopwords/中文停用词库.txt, stopwords/stopword.txt ] stopwords load_stopwords(stopword_files) def segment(text): 分词并过滤停用词 words jieba.lcut(text) return [w for w in words if w not in stopwords and len(w.strip()) 0]这段代码的逻辑是先加载所有停用词到内存分词后逐个过滤。参数len(w.strip()) 0是为了去掉空白字符。注意jieba.lcut返回的是列表如果评论量很大可以考虑用jieba.lcut_for_search提高召回但会增加计算量。停用词表不是越多越好过度过滤可能把“不”这种关键否定词也删掉——检查一下四份停用词表里有没有包含“不”、“没”、“无”如果有需要在过滤前把它们从停用词集合中移除。3.2 情感词典的加载与匹配策略情感词典是这套系统的灵魂。posdict.txt和negdict.txt分别存正面词和负面词mostdict.txt大多数、verydict.txt非常、ishdict.txt稍许、insufficientdict.txt不够是程度副词inversedict.txt是否定词。打分的基本思路是遍历分词结果遇到情感词就查词典拿基础分遇到程度副词就乘系数遇到否定词就翻转极性。def load_dict(filepath): 加载词典文件每行一个词 with open(filepath, r, encodingutf-8) as f: return set(line.strip() for line in f if line.strip()) pos_dict load_dict(posdict.txt) neg_dict load_dict(negdict.txt) most_dict load_dict(mostdict.txt) # 程度大多数系数 1.5 very_dict load_dict(verydict.txt) # 程度非常系数 1.8 ish_dict load_dict(ishdict.txt) # 程度稍许系数 0.8 insufficient_dict load_dict(insufficientdict.txt) # 程度不够系数 0.6 inverse_dict load_dict(inversedict.txt) # 否定词翻转极性 # 程度副词系数映射 degree_map {} for w in most_dict: degree_map[w] 1.5 for w in very_dict: degree_map[w] 1.8 for w in ish_dict: degree_map[w] 0.8 for w in insufficient_dict: degree_map[w] 0.6这里的关键参数是程度系数。1.5、1.8、0.8、0.6 这组值是常见经验值不是唯一解。如果你发现“非常差”和“差”的分数差距不够大可以把very_dict的系数调到 2.0如果“稍许不满”被过度放大把ish_dict降到 0.5。调参的依据是验证集上的准确率不是拍脑袋。3.3 打分函数与否定词窗口打分函数的核心难点在于否定词的作用范围。比如“不是很好”否定词“不”修饰的是“好”应该翻转成负面。但“不是不好”双重否定又变回正面。常见做法是维护一个否定词计数遇到情感词时根据计数奇偶决定是否翻转。def score_sentence(words): 对分词后的列表进行情感打分 score 0 neg_count 0 # 否定词计数 for i, word in enumerate(words): if word in inverse_dict: neg_count 1 continue if word in pos_dict or word in neg_dict: base 1.0 if word in pos_dict else -1.0 # 检查前一个词是否是程度副词 if i 0 and words[i-1] in degree_map: base * degree_map[words[i-1]] # 否定词翻转 if neg_count % 2 1: base -base score base neg_count 0 # 情感词消费掉否定词 return score这段代码里neg_count在遇到情感词后被重置意味着否定词只影响最近的一个情感词。这是简化处理实际语言中否定词可能跨多个词起作用比如“不算是特别好”。如果要更精细可以设置一个窗口大小比如否定词后 3 个词内都受影响。但窗口越大误判风险越高。我一般会先用窗口为 1 的版本跑基线再根据错误案例决定是否扩大。提示emotion_score.py里如果有if __name__ __main__块可以直接单独运行它来测试打分函数不用每次都走run.py的全流程。调试阶段这样效率更高。4. 避坑与排查词典路径、编码和分数异常怎么处理4.1 词典文件读取报 UnicodeDecodeError现象运行run.py时抛出UnicodeDecodeError: gbk codec cant decode byte...程序中断。原因Windows 中文环境下Python 默认用 GBK 编码打开文件但词典文件实际是 UTF-8 编码。open()函数没有显式指定encodingutf-8时就会翻车。解决把所有open()调用统一加上encodingutf-8。如果某个文件确实是 GBK 编码用chardet检测后单独处理。批量修改可以用编辑器全局替换open(为open(..., encodingutf-8)但注意不要改到二进制文件的读取。4.2 所有评论得分都是 0 或接近 0现象跑完pos.rar和neg.rar里的评论发现正面和负面的分数没有明显区分大量结果为 0。原因最常见的是词典路径不对load_dict读到了空集合。其次是分词结果和词典条目粒度不一致比如词典里是“干净”分词结果是“干”、“净”分开。解决在load_dict后加一行print(f{filepath}: {len(result)} words)确认每个词典加载了多少词。正常情况posdict.txt应该有几百到上千条。如果输出是 0检查路径是相对路径还是绝对路径——run.py的工作目录和emotion_score.py的工作目录可能不同。粒度问题可以用jieba.add_word(干净)把领域词加进自定义词典。4.3 否定词导致情感极性判断反了现象“不推荐”被判成正面“不是很好”被判成强正面。原因否定词表inversedict.txt不完整或者否定词计数逻辑有 bug。比如“不”和“推荐”之间隔了其他词neg_count在遇到“推荐”之前被重置了。解决先检查inversedict.txt里有没有“不”、“没”、“无”、“非”、“莫”、“勿”这些常见否定词。然后检查score_sentence里neg_count的重置时机——只在遇到情感词后重置遇到其他词不重置。如果否定词和情感词之间隔了程度副词比如“不是很满意”程度副词“很”会先被处理但neg_count仍然保留这个顺序是对的。4.4 词云生成中文显示为方块现象wordcloud.jpg重新生成时中文全部变成方框。原因wordcloud默认字体不支持中文需要指定中文字体路径。解决在WordCloud构造函数里加font_path参数指向系统里的中文字体文件。Windows 常见路径是C:\Windows\Fonts\simhei.ttfmacOS 是/System/Library/Fonts/PingFang.ttc。如果找不到字体把酒店评论情感分析.docx里用到的字体文件复制到项目目录也行。4.5 备份文件 .zbak 被误读现象修改词典后结果异常想恢复但不知道原始文件在哪。原因目录里同时存在ishdict.txt和ishdict.txt.zbak代码读取的是不带后缀的版本但手动改错了没有备份。解决.zbak文件就是后悔药。直接用copy ishdict.txt.zbak ishdict.txt覆盖回去。建议在改任何词典之前先手动复制一份到backup/目录命名带上日期比如posdict_20250101.txt。这样即使.zbak也被覆盖了还有第二层保险。5. 从课程设计到可展示成果词云、PPT 与分数分布调优5.1 用词云把情感分析结果可视化词云是答辩时最直观的展示手段。wordcloud.jpg已经有一张现成的图但如果你想用自己的数据重新生成可以按下面的方式做。核心思路是把正面评论和负面评论分开分别生成词云对比哪些词在正面中出现频率高、哪些在负面中出现频率高。from wordcloud import WordCloud import matplotlib.pyplot as plt import jieba def generate_wordcloud(texts, stopwords, font_path, output_path): 生成词云并保存 # 合并所有文本并分词 all_words [] for text in texts: words jieba.lcut(text) all_words.extend([w for w in words if w not in stopwords and len(w) 1]) # 用空格连接WordCloud 需要字符串输入 text_joined .join(all_words) wc WordCloud( font_pathfont_path, # 中文字体路径必须指定 width800, height600, background_colorwhite, max_words100, # 最多显示 100 个词 collocationsFalse # 避免重复词组合 ) wc.generate(text_joined) wc.to_file(output_path) print(f词云已保存到 {output_path}) # 使用示例 font C:/Windows/Fonts/simhei.ttf # 根据系统调整 generate_wordcloud(pos_texts, stopwords, font, pos_wordcloud.png) generate_wordcloud(neg_texts, stopwords, font, neg_wordcloud.png)参数max_words控制显示词数太多会显得杂乱100 到 150 比较合适。collocationsFalse很重要否则wordcloud会自动把相邻词组合成短语中文场景下容易产生无意义的组合。生成两张图后正面词云里“干净”、“方便”、“满意”会比较大负面词云里“吵”、“旧”、“差”会比较突出答辩时一眼就能看出区分度。5.2 分数分布验证与阈值调整情感分析系统最终要给出分类结果通常需要一个阈值分数大于某个值判正面小于某个值判负面中间判中性。这个阈值不是固定的需要根据你的数据分布来调。import pandas as pd def evaluate_threshold(scores, labels, threshold_range): 遍历阈值范围找最佳分类阈值 best_acc 0 best_th 0 for th in threshold_range: preds [] for s in scores: if s th: preds.append(1) # 正面 elif s -th: preds.append(-1) # 负面 else: preds.append(0) # 中性 acc sum(1 for p, l in zip(preds, labels) if p l) / len(labels) if acc best_acc: best_acc acc best_th th return best_th, best_acc # 假设 scores 是打分结果列表labels 是人工标注的标签 # threshold_range 从 0.5 到 3.0步长 0.1 thresholds [x * 0.1 for x in range(5, 31)] best_th, best_acc evaluate_threshold(scores, labels, thresholds) print(f最佳阈值: {best_th}, 准确率: {best_acc:.2%})这段代码的逻辑是遍历一系列阈值对每个阈值计算分类准确率取最高的那个。threshold_range的范围要根据你的打分尺度来定——如果单条评论分数普遍在 -5 到 5 之间阈值从 0.5 到 3.0 就够了。如果分数普遍偏小比如 -2 到 2阈值范围要相应缩小。跑完这个评估你会得到一个数据驱动的阈值比拍脑袋定 0 或 1 靠谱得多。5.3 答辩 PPT 里该放什么酒店评论情感分析.pptx已经提供了模板但内容需要根据你的实际运行结果更新。我一般会放四页核心内容第一页放系统架构图说明数据从评论输入到分数输出的完整链路第二页放词典匹配的示例拿一条真实评论逐词标注哪些是情感词、哪些是程度副词、哪些是否定词第三页放分数分布直方图展示正面和负面评论的分数分离程度第四页放词云对比图正面一张、负面一张。如果老师问“为什么不用深度学习”回答思路是课程设计的核心目标是理解情感分析的基本原理和完整流程词典方法每一步都可解释、可调试适合在有限时间内完成并讲清楚。深度学习需要标注数据和 GPU 资源对于这个规模的任务来说性价比不高。这个回答既诚实又体现了工程判断力。从那以后我每次拿到带词典的情感分析项目都会先跑一遍基线、再手动构造边界案例测试否定词逻辑、最后用分数分布验证阈值合理性这三步走完基本不会在答辩时被问倒。希望这份拆解能帮你把这份酒店评论情感分析系统顺利跑起来改出属于自己的版本。本文还有配套的精品资源点击获取