外卖评价情感倾向性分析:词典打分与Python实现

发布时间:2026/9/16 3:19:20

外卖评价情感倾向性分析:词典打分与Python实现 简介针对外卖平台用户评价的情感倾向性分析需求这份打包资料提供了一套基于Python的完整实践方案适合自然语言处理初学者或数据分析入门者参考学习。资源共12个文件压缩包仅3.23MB包含可运行的源码、评论文本数据集、正负向候选词字典、处理结果可视化图片以及详细的设计思路报告和简要说明文档便于从数据到结果逐步复盘。目前已有852人进入学习热度适中。读者可从中掌握将原始评论按情感倾向拆分为正向与负向文件的具体做法例如读取前4000条归入正向、后8000条归入负向并结合词频统计与可视化观察两类评分的语言特征。设计思路报告对需求背景、数据划分和实现流程做了完整梳理有助于快速迁移到其他情感分析场景进一步提升文本处理与结果呈现能力。1. 外卖评价情感倾向性分析的词典打分与文件落盘“骑手在楼下等了十分钟态度很好包装也严实”和“超时四十分钟汤全洒了打电话还不接”这两条评论给到同一个商家后者几乎必然被平台标记为差评。外卖评价情感倾向性分析要做的就是从这类短文本里判定评论人的情绪极性并把它转成可落盘、可统计分析的数据。这个资源不依赖BERT微调也不训练贝叶斯分类器而是走基于情感词典的极性匹配路线把评论切词后与正负向候选词表比对按命中情况计算得分再按阈值把每条评论写入正向或负向文件。配套文件覆盖了完整闭环review.csv评论数据、code.py主程序、pos_candi与neg_candi候选情感词、设计思路报告以及正负向高频词可视化图。适合文本挖掘课程设计、想快速验证情感分类效果的Python开发者以及需要向业务方解释“这条评论为什么是差评”的可解释性分析场景。2. 评论语料读取与候选情感词加载策略情感词典方案的第一道工序不是打分而是把原始语料和词表都变成程序可直接操作的数据结构。外卖评论和新闻语料不一样句式短、口语词多、还混着“叮咚”“骑手”这类场景词任何一步清洗不到位都会在后面的匹配阶段放大误差。2.1 数据形态与CSV读取细节review.csv是典型的平台导出数据字段里至少包含评论正文和评分。直接用Python内置的csv模块也能读但在列名不稳定、有空值时处理麻烦我一般用pandas先把全表拉进来做一次形态确认import pandas as pd # 平台导出的csv常见编码是utf-8或gbkutf-8-sig能兼容带BOM的文件 df pd.read_csv(review.csv, encodingutf-8-sig) print(df.shape) print(df.columns.tolist()) print(df.head(3).to_string())这段代码先把csv读成DataFrame随后打印行列数、字段名和前3条记录。encoding是这里最容易踩坑的参数Windows下导出的文件常是gbk编码直接读会抛UnicodeDecodeError改成encodinggbk即可utf-8-sig则能自动剥离Excel生成的BOM头避免第一列字段名出现“\ufeff”前缀。对外卖评论这种高噪声文本列名确认比数据条数更重要comment_text字段名在不同版本脚本里可能叫comment或content程序里要统一引用实际列名。字段形态大致如下表label这一列在原始导出里不一定存在需要在预处理阶段根据业务口径生成。字段类型说明order_idstr订单号可能大量重复ratingint15星评分comment_textstr评论文本可能有空值labelint1为正向-1为负向预处理阶段生成2.2 中文分词与停用词过滤词典匹配的前提是分词。英文按空格切就可以中文必须用分词工具把句子切成“骑手 / 态度 / 很好 / 包装 / 严实”这样的词序列。这个资源里选择jieba做精确模式分词是中文情感分析场景里最常见也最不折腾的配置import jieba def cut_words(text: str) - list[str]: 把单条评论文本切成词列表去掉纯空白后返回 if not isinstance(text, str): return [] words jieba.lcut(text.strip()) # 这里不按长度过滤单字情感词如“好”“慢”要保留给词典匹配 return [w for w in words if w.strip()]jieba.lcut返回的是精确模式分词结果适合外卖评论这种几十字的短文本全模式会切出大量冗余词组合搜索引擎场景才用得上。函数里做了两件小事非字符串输入直接返回空列表避免空值评论让下游报错只过滤纯空白不在这里砍单字词原因是“好”“慢”“差”本身就是强情感信号砍掉它们会让召回率明显下降。停用词过滤在这个方案里可以推迟到高频词统计阶段做因为词典匹配本身只会命中候选词表里的词无关词对得分没有贡献。2.3 候选情感词文件的标准化pos_candi.txt和neg_candi.txt是从语料里统计出来的候选情感词格式是每行一个词。直接读文件时最容易遇到三类问题行尾换行符残留、空行混入、同一个词大小写或空格不一致。加载逻辑里统一做一次标准化def load_lexicon(path: str) - set[str]: with open(path, r, encodingutf-8) as f: words {line.strip() for line in f if line.strip()} # 过滤长度大于4的词保留单字情感词和常见双字词 return {w for w in words if 1 len(w) 4} pos_words load_lexicon(pos_candi.txt) neg_words load_lexicon(neg_candi.txt)这里用集合推导式一次性完成去重、去空行和strip长度控制在1到4个字符是为了过滤掉“味道真的非常好吃”这类包含多个词的污染行。候选词表是外部生成的结果导入后可以先打印词表大小如果pos文件只有几十个词说明统计阶段的频次阈值设高了匹配阶段会出现大量评论被判为中性。提示候选词文件必须和code.py放在同一级目录运行前用os.path.exists检查一下避免路径硬编码导致在IDE里能跑、命令行跑就报FileNotFoundError。3. 词典打分模型与正负样本分流写入词表和分词器就绪后进入核心环节对每条评论计算情感得分再按标签写入不同文件。这一步的工程要点是打分规则要可解释、参数要能调而不是追求一个黑盒准确率。3.1 情感得分算法极性累计与否定词取反最朴素的情感词典打分是统计命中正负词的数量做差。外卖评论里的转折和否定表达很多单纯做差会把“味道不错但送得太慢”打成正分。因此代码里处理了否定词取反否定词命中后相邻的极性词翻转符号negation_words {不, 没, 没有, 不太, 不怎么} def feel_score(words: list[str]) - float: score 0 negation False for w in words: if w in negation_words: negation True continue if w in pos_words: if negation: score - 1 # “不好”视为负向 else: score 1 negation False elif w in neg_words: if negation: score 1 # “不慢”视为正向 else: score - 1 negation False # 归一化避免长文本天然占优 return score / max(1, len(words))逻辑说明遍历分词结果遇到否定词只改状态不计分命中正向词时若前面是否定态则记为负向分否则正向分命中负向词相反。每处理完一个极性词就把否定态复位避免“不太满意”这种连续否定被二次翻转。分母用max(1, len(words))做归一化把分数压到[-1, 1]长评论不会因为词多而得分更高。下面是参数的含义参数含义建议值negation_words否定词表命中后翻转下一个极性词符号覆盖“不”“没”“不太”“不怎么”即可score 0判为正向正负样本不平衡时可上调到0.05score 0判为负向同上score 0判为中性需单独落盘观察3.2 分类写入正向与负向文件得分算出来后把每条评论原样写入对应文件。写入时采用utf-8-sig编码这是决定Excel能否直接打开不乱码的关键参数pos_f open(reviews_pos.txt, w, encodingutf-8-sig) neg_f open(reviews_neg.txt, w, encodingutf-8-sig) neutral_f open(reviews_neutral.txt, w, encodingutf-8-sig) for comment in df[comment_text]: words cut_words(comment) s feel_score(words) if s 0: pos_f.write(comment \n) elif s 0: neg_f.write(comment \n) else: neutral_f.write(comment \n) pos_f.close() neg_f.close() neutral_f.close()这段代码的意图是把模型判断结果固化到磁盘后续高频词统计、可视化全部基于这三个文件而不是在内存里重算。中性评论单独落盘是个好习惯外卖场景里“s0才正向”的阈值会把纯事实描述“送达时间19:30”推到中性文件这些样本是后续调阈值的重要依据。注意写入时逐条加\n防止最后一条评论没有换行符。3.3 前4000与后8000种子样本切分与评测隔离摘要里提到的“读取前4000条写入正向文件后8000条写入负向文件”本质是种子样本切分不是模型预测结果。review.csv的实际排列往往按业务规则排过序前4000条对应评分4星以上的好评后8000条对应2星以下的差评。这个切分动作有两个用途一是从这两批种子样本里统计高频候选词生成pos_candi与neg_candi二是作为后续词典匹配结果的对照集用来算召回率。代码里的实现通常是这样# 种子样本切分前4000条作为正向语料后8000条作为负向语料 positive_seed df.iloc[:4000][comment_text] negative_seed df.iloc[4000:12000][comment_text] positive_seed.to_csv(positive_seed.txt, indexFalse, headerFalse, encodingutf-8-sig) negative_seed.to_csv(negative_seed.txt, indexFalse, headerFalse, encodingutf-8-sig)这里的关键是评测隔离种子语料只用于生成候选词表和观察词频分布模型打分的对象是切分后的全量数据。如果拿种子样本同时去统计词表和评估准确率属于数据泄漏得到的指标会虚高。原代码把这两个阶段分开先切分种子样本再基于词典对全量评论做推断并写入文件流程上是干净的。下表总结了两个阶段的边界阶段输入输出用途样本切分review.csv前12000条positive_seed.txt / negative_seed.txt生成候选情感词、验证词典覆盖率词典打分全量评论切词结果reviews_pos.txt / reviews_neg.txt / reviews_neutral.txt业务侧的情感分类落盘4. 高频词统计与matplotlib可视化图像打分落盘之后评价分析还不能算结束。外卖评论的情感分析最终要给业务方一个直觉结论正向评论里出现最多的词是什么负向评论里又在抱怨什么这一步用词频统计加可视化完成输出就是资源里的正向高频.png与负向高频.png。4.1 用Counter统计正负向评论的高频词Python标准库collections.Counter做词频统计足够高效12000条评论处理时间在秒级。统计时要把候选词典本身剔除否则“好吃”“差评”这些词必然霸榜看不到业务侧的真实表达from collections import Counter def top_words(file_path: str, top_n: int 15) - list[tuple[str, int]]: counter Counter() with open(file_path, r, encodingutf-8) as f: for line in f: counter.update(cut_words(line)) # 去掉情感词典命中的词剩余词反映业务侧关注点 stop_words pos_words | neg_words return [item for item in counter.items() if item[0] not in stop_words][:top_n] pos_common top_words(reviews_pos.txt) neg_common top_words(reviews_neg.txt)counter.update(cut_words(line))是对每条评论先切词再把词列表合并进Counter实例等价于遍历所有词逐个加1。返回结果用[:top_n]截断前15项注意要先把词典词过滤掉再截断否则高频位置被候选词占满。这一步的细节是停用词过滤放在这里比放在分词阶段更合理因为“这”“了”“的”等高频虚词在这个环节被剔除不会影响词典匹配。4.2 中文字体配置与水平条形图绘制matplotlib画图有两个经典坑中文显示成方块、负号显示成乱码。根源是默认字体不支持中文需要在画图前全局指定字体import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei, Noto Sans CJK SC] plt.rcParams[axes.unicode_minus] False def draw_bar(data: list[tuple[str, int]], title: str, save_path: str) - None: words, counts zip(*data) plt.figure(figsize(8, 6)) plt.barh(range(len(words)), counts, color#4C72B0) plt.yticks(range(len(words)), words) plt.title(title) plt.gca().invert_yaxis() plt.tight_layout() plt.savefig(save_path, dpi150) plt.close() draw_bar(pos_common, 正向高频词 Top15, 正向高频.png) draw_bar(neg_common, 负向高频词 Top15, 负向高频.png)font.sans-serif列表里按OS顺序填了Windows的SimHei、微软雅黑和Linux的Noto Sans CJK程序换机器不会立刻崩。axes.unicode_minusFalse用来解决坐标轴负号渲染问题。条形图用barh横向画词在y轴频次在x轴比纵向柱状图更易读词长和频次关系一目了然。invert_yaxis让频次最高的词在顶部更符合阅读习惯。4.3 从高频图里读业务结论负向高频.png里通常会出现“慢”“漏”“凉”“差”“等”这类词正向高频.png则集中在“快”“好吃”“干净”“态度”上。这不是巧合而是外卖场景的真实痛点分布时效、配送完整性、餐品温度构成差评主因口味、卫生、服务构成好评主因。观察两张图的差异还能反过来检查词典质量——如果负向高频图里出现“不错”“划算”说明有大量正极性评论被误判进了负向文件这时应回头查否定词表和阈值而不是先调分词器。5. 调优词典与验证分类质量的三个动作5.1 用中性样本率校准阈值reviews_neutral.txt的大小是调整阈值的第一信号。全量评论里中性占比超过30%说明阈值0的判定太保守很多带弱情感倾向的评论没被捕获。常见做法是把阈值从s 0改到s 0.05同时负向阈值改到s -0.05中间的样本全部归入中性。调整后在控制台打印三个文件的行数对比偏移量一般中性占比降到20%以内是健康状态。5.2 转折词切分消除双极性抵消“味道不错但送得慢”这种评论在3.1节的朴素模型里正负互相抵消得分接近0被丢进中性文件。这类评论恰好是差评的高潜样本——用户对核心体验不满只是先肯定了次要维度。处理方式是遇到“但”“不过”“就是”时把句子切成两段只对后段打分def split_by_turn(words: list[str]) - list[str]: for i, w in enumerate(words): if w in {但, 但是, 不过, 就是}: return words[i 1:] return words在feel_score开头调用split_by_turn后段保留转折之后的真实评价意图。注意“就是”在口语里也用于强调正面如“就是快”所以“就是”放到转折词表后要注意看高频图中的负面词变化。5.3 把误判样本的实义词回流到词典从正向高频.png里挑选与业务相关但没被pos_candi覆盖的词比如“新鲜”“实惠”“准时”手动追加到pos_candi.txt负向文件里的“漏洒”“串味”“不接”等追加到neg_candi.txt。每次追加后重跑全量流程对比两轮高频图的词频变化区间就能判断词典迭代是提升召回还是引入噪声。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/9/16 3:19:20

solvePnP相机位姿估计:tvec坐标变换与二维码定位实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/16 3:14:19

前端规范体系落地指南:从代码风格到Git提交与接口协作

先聊个很多人没弄明白的事:前端规范不是用来“限制”人的,它是用来“救”人的。我见过太多项目,前期跑得飞快,代码随便写,等到了第6个月、第8个月,新需求来了,改一个老功能要翻半天文件&#xf…

2026/9/16 4:24:22

Intern-S1-Pro:万亿参数背后的可解释科学AI范式

1. 这不是又一个“参数堆砌”噱头:Intern-S1-Pro的万亿级究竟在算什么?“全球首个万亿参数科学模型开源”——看到这个标题,我第一反应不是兴奋,而是皱眉。过去三年里,我亲手部署过17个标称“超大参数”的开源模型&…

2026/9/16 4:24:22

YOLO融合大模型的电子元器件智能识别:从检测到认知的闭环实战

大概两年前,我因为在产线上帮朋友解决一个实际需求,开始接触电子元器件的智能识别:质检工位每天要人工检查几万个电阻、电容、二极管、芯片,眼睛盯到发花,漏检率和误判率一旦上来,后面组装工序全跟着遭殃。…

2026/9/16 4:24:22

智能体实战指南:从0到1搭建可用AI智能体的完整路径

1. 从"聊天玩具"到"数字员工":智能体到底解决什么问题先说个现象。过去两年我接触过大量做AI应用的朋友,大家早期都热衷于调大模型、写提示词、接API,做出来一堆"能聊天"的东西。但聊归聊,真要落地…

2026/9/16 4:24:22

8卡H20部署DeepSeek-V3-0324实战:显存规划与性能调优全记录

8卡H20跑DeepSeek-V3-0324,光听这个组合就很有反差感。一边是显存管够但算力被收过的NVIDIA H20,一边是671B总参数、37B激活参数的MoE大模型,单从账面上看,很多人第一反应是这卡跑V3会特别吃力。实际上我们连续测了两周&#xff0…

2026/9/15 4:54:30

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/16 0:04:09

PHP源码部署实战:从环境配置到运行情侣游戏全攻略

简介:这是一套面向情侣互动场景的PHP完整源码,集成情侣飞行棋、真心话大冒险、情趣骰子等玩法,并内置完整分销制度,可自定义多种返佣比例,源码完全开源无加密,支持微信无感自动授权登录与第三方授权&#x…

2026/9/15 14:22:53

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/15 21:31:11

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/15 11:42:23

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码