☰
基于DeepSeek的千万级餐饮评论分析:从数据清洗到菜单优化实战
2026/9/30 9:47:25 网站建设 项目流程

简介:这份PDF文档面向餐饮从业者、数据分析初学者及希望将大模型落地业务场景的读者,以「用DeepSeek分析千万评论数据优化菜单」为主线,完整呈现从数据采集到业务决策的全流程。内容涵盖餐饮业现状与数据驱动必要性、DeepSeek技术原理与优势、外卖平台与点评网站等多源评论数据的爬取与预处理、数据清洗与TF-IDF及词嵌入等特征提取方法,并深入讲解情感分析、主题挖掘与关联规则挖掘在用户偏好洞察中的具体应用,最终落到菜单调整、套餐组合设计与成本利润平衡等可执行策略。文档还包含代码示例、开发要点、效果评估指标对比及案例总结展望,共26页,目录结构清晰、图表完整。资源包为1个PDF文件,大小约1.86MB,已有100人学习。读者可借此掌握一套可复用的评论数据分析与菜单优化方法论,理解大模型在餐饮经营决策中的实际价值。

1. 千万条评论压垮 Excel 之后:这份 26 页 PDF 到底给了什么

去年帮一个连锁快餐品牌做菜单诊断,运营把三个外卖平台加点评站点的评论导出来,CSV 一共 47 个文件、压缩后 1.8G,用 Excel 打开直接卡死,用 pandas 读一遍内存飙到 12G。那一刻我才真正理解,为什么“餐饮评论数据集”这个词最近被搜得这么频繁——不是大家不想分析,是数据量一上来,传统做法全线崩。这份《餐饮业突围:用DeepSeek分析千万评论数据优化菜单的案例》PDF 一共 26 页,讲的正是这条链路:从多源评论采集、清洗、特征提取,到用 DeepSeek 做情感分析、主题挖掘、关联分析,最后落到菜单的保留、改进、淘汰和套餐组合。它适合两类人:一是手里已经攒了几万到千万级评论、想把它变成菜单决策的餐饮数据从业者;二是想找一个完整 NLP 落地案例来练手 DeepSeek 的工程师。下面我按自己复现的顺序,把这份文档拆开讲。

2. 数据从哪来、怎么洗:千万级评论的采集与预处理链路

2.1 四类评论源的取舍与采集方式

文档把评论来源分成四类:外卖平台、餐厅官网与社交媒体、点评类网站、在线旅游平台。这个分类不是凑数,它对应的是四种完全不同的数据形态和采集成本。外卖平台评论短、口语化、带评分和订单信息,结构化程度最高;点评类网站评论长、有环境/服务/菜品多维评分,但反爬最严;社交媒体评论散、带表情和网络梗,噪声最大;在线旅游平台的评论往往和“地方特色”“游客视角”绑定,对景区店特别有价值。

采集方式上,文档给了三条路:爬虫、API、人工。我的经验是,能走 API 就别写爬虫,API 返回的字段稳定、有分页游标、不会因为页面改版一夜失效。爬虫只在平台没有开放接口、且你确认过使用条款允许的范围内用。人工收集看着笨,但现场纸质评价表和电话回访拿到的信息深度,是线上评论给不了的,量小但质高,适合做种子标注集。

import requests from bs4 import BeautifulSoup url = 'https://example.com/reviews' # 替换为实际评论页 headers = {'User-Agent': 'Mozilla/5.0'} # 基础请求头,降低被拦概率 resp = requests.get(url, headers=headers, timeout=10) if resp.status_code == 200: soup = BeautifulSoup(resp.text, 'html.parser') # 选择器要按目标站点真实 DOM 结构调整,别照抄 reviews = soup.find_all('div', class_='review-item') for r in reviews: print(r.get_text(strip=True)) else: print('请求失败', resp.status_code)

这段代码的关键不在语法,在三个参数:headers里的 UA 决定你能不能拿到正常页面;timeout防止单请求挂死拖垮整批任务;class_='review-item'必须换成目标站点真实类名,照抄必空。批量采集时我一般会加随机间隔和失败重试,单机 QPS 压到 1 以下,既稳又不至于给对端造成压力。

2.2 清洗四步:去重、缺失、纠错、去噪

文档把清洗拆成去除重复评论、处理缺失值、纠正拼写语法错误、去除无关信息四步,顺序有讲究。去重必须放第一步,否则后面所有统计都被重复样本放大。缺失值处理要看缺失比例:评分缺失低于 5% 直接删记录,高于 5% 用均值或中位数填充,但要在日志里记下填充了多少条,否则后面做满意度对比时数据口径就乱了。

import pandas as pd import re data = pd.read_csv('restaurant_reviews.csv') # 1. 去重:按评论内容判重,保留第一条 data = data.drop_duplicates(subset=['review_content'], keep='first') # 2. 缺失值:评分用均值填充,评论内容为空的直接删 data['rating'] = data['rating'].fillna(data['rating'].mean()) data = data[data['review_content'].notna()] # 3. 去噪:去掉 HTML 标签、链接、特殊符号 def clean_text(text): text = re.sub(r'<.*?>', '', text) # HTML 标签 text = re.sub(r'http\S+', '', text) # 链接 text = re.sub(r'[^\w\s\u4e00-\u9fa5]', '', text) # 保留中英文数字 return text.strip() data['review_content'] = data['review_content'].apply(clean_text) data.to_csv('cleaned_reviews.csv', index=False)

\u4e00-\u9fa5这个区间是中文汉字范围,很多清洗脚本只写[^\w\s],结果把中文全删了,这是血泪经验。纠错那步文档提了 pyspellchecker,但中文评论里拼写错误远少于错别字和网络缩写,实际项目里我更多用同义词归一表来处理,比如“好吃/赞/绝了”统一映射到正向词,比通用拼写库管用。

2.3 特征提取:词频、TF-IDF 与词嵌入怎么选

文档列了词频统计、TF-IDF、词嵌入三种方法,它们不是替代关系,是不同阶段用不同工具。词频统计最快,用来做第一轮关键词摸底,看消费者到底在聊什么;TF-IDF 用来压掉“好吃”“不错”这类高频但无区分度的词,突出真正有信息量的特征;词嵌入用来把词映射到向量空间,为后面的聚类和关联分析做准备。

from sklearn.feature_extraction.text import TfidfVectorizer from gensim.models import Word2Vec import numpy as np # TF-IDF:max_features 控制维度,避免稀疏矩阵过大 vectorizer = TfidfVectorizer(max_features=5000, ngram_range=(1, 2)) tfidf_matrix = vectorizer.fit_transform(data['review_content']) # Word2Vec:min_count 过滤低频词,vector_size 决定向量维度 sentences = [text.split() for text in data['review_content']] w2v = Word2Vec(sentences, vector_size=100, min_count=5, window=5) def review_vector(text): vecs = [w2v.wv[w] for w in text.split() if w in w2v.wv] return np.mean(vecs, axis=0) if vecs else np.zeros(100) data['review_vec'] = data['review_content'].apply(review_vector)

max_features=5000是经验值,评论量在十万级时够用,千万级可以放到 2 万;ngram_range=(1,2)让“不好吃”这种二元否定被单独识别,不然分词后“不”和“好吃”分开,情感直接判反。min_count=5是过滤只出现一两次的噪声词,设太小模型学不到东西,设太大长尾菜品名会被丢掉。

3. 用 DeepSeek 挖需求:情感、主题、关联三件套怎么落地

3.1 模型选型与微调:为什么不是直接调 API

文档在模型选型部分给了两条路:直接用预训练模型做推理,或在餐饮评论数据上微调。我的判断是,如果你只是做情感二分类和关键词抽取,直接调 DeepSeek 的 API 就够了,成本低、上手快;但如果你要做细粒度的方面级情感分析——比如同一条评论里“菜好吃但服务差”——那就需要微调,因为通用模型对餐饮领域的方面词边界不敏感。

from transformers import AutoTokenizer, AutoModelForSequenceClassification import torch model_name = "bert-base-chinese" # 文档示例用的基座,实际可换更强中文模型 tokenizer = AutoTokenizer.from_pretrained(model_name) model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=3) # num_labels=3 对应 负向/中性/正向,别用 2,餐饮评论中性占比很高 texts = ["这道菜味道很不错", "分量太少了", "一般般吧"] inputs = tokenizer(texts, padding=True, truncation=True, max_length=128, return_tensors='pt') with torch.no_grad(): logits = model(**inputs).logits preds = torch.argmax(logits, dim=1) print(preds)

num_labels=3是我强烈建议的改动。文档示例里用了 2 分类,但真实餐饮评论里“还行”“一般”这类中性表达占比能到三成,强行二分会把大量中性样本推到正向或负向,导致满意度虚高或虚低。max_length=128对短评论够用,长评论建议截断前 128 再补一条摘要,不然关键信息可能在后半段被切掉。

3.2 主题挖掘:从评论里捞出“上菜慢”和“分量小”

情感分析告诉你整体满意不满意,主题挖掘告诉你具体满意在哪、不满在哪。文档提了主题模型,实操里我用得最多的是 LDA 加关键词人工命名。跑完 LDA 会得到若干主题,每个主题是一组高概率词,比如“等/慢/上菜/时间”聚成一类,你把它命名为“出餐速度”;“少/小/不够/分量”聚成一类,命名为“分量感知”。

from sklearn.decomposition import LatentDirichletAllocation from sklearn.feature_extraction.text import CountVectorizer cv = CountVectorizer(max_features=3000, max_df=0.9, min_df=5) dtm = cv.fit_transform(data['review_content']) lda = LatentDirichletAllocation(n_components=8, random_state=42) lda.fit(dtm) words = cv.get_feature_names_out() for idx, topic in enumerate(lda.components_): top_words = [words[i] for i in topic.argsort()[:-11:-1]] print(f'主题{idx}: {top_words}')

n_components=8不是固定值,一般先跑 5 到 15 个主题,看哪个数量下主题之间区分度最好。max_df=0.9是压掉出现在 90% 以上文档里的词,这类词基本没有区分度;min_df=5是过滤低频词。跑出来的主题一定要人工命名,机器给的是词簇,业务含义得你来贴标签,这一步偷懒后面菜单策略就会跑偏。

3.3 关联分析:找出“点了 A 的人大概率也点 B”

关联分析是这份文档里最容易被忽略但商业价值最高的一节。它用的是关联规则挖掘,核心指标是支持度、置信度、提升度。支持度是“A 和 B 同时出现”的比例,置信度是“点了 A 的人里有多少也点了 B”,提升度是“这个组合比随机搭配高多少”。提升度大于 1 才有意义,等于 1 说明两个菜独立,硬凑套餐没价值。

from mlxtend.frequent_patterns import apriori, association_rules import pandas as pd # basket 是订单-菜品 0/1 矩阵,行是订单,列是菜品 frequent = apriori(basket, min_support=0.02, use_colnames=True) rules = association_rules(frequent, metric='lift', min_threshold=1.2) # 按提升度排序,取前 20 条看组合 rules = rules.sort_values('lift', ascending=False).head(20) print(rules[['antecedents', 'consequents', 'support', 'confidence', 'lift']])

min_support=0.02意味着组合至少出现在 2% 的订单里,设太高会漏掉长尾组合,设太低会跑出一堆偶然共现。min_threshold=1.2是提升度门槛,1.2 表示比随机高 20%,低于这个值的组合不值得做成套餐。这套跑完,你手里就有了一张“哪些菜该放一起推荐”的清单,比拍脑袋组套餐靠谱得多。

4. 避坑与排查:千万级评论分析里最容易翻车的五件事

4.1 内存爆掉:pandas 默认读法撑不住千万行

现象是脚本跑到read_csv就卡死或直接 OOM。原因是 pandas 默认把整列推断成 object,中文评论列内存占用是实际文本的好几倍。解决办法是分块读加指定 dtype,chunksize=100000逐块处理,文本列显式声明为 string,数值列用 int32/float32 而不是默认的 int64/float64,内存能降一半以上。

4.2 情感判反:否定词和反讽没处理

现象是“不难吃”“还行吧”被判成负向,“真是绝了”在差评语境里被判成正向。原因是分词把否定词和情感词切开了,模型看不到否定修饰。解决办法是分词阶段用自定义词典把“不难吃”“不好吃”绑成整体,或者在微调数据里专门标注一批反讽样本,让模型学到语境。

4.3 主题跑偏:停用词表没针对餐饮领域

现象是跑出来的主题里全是“的”“了”“就是”“感觉”这类词,看不出业务含义。原因是通用停用词表没覆盖餐饮评论的高频虚词。解决办法是先用词频统计跑一遍,把 top 50 里没有业务含义的词手动加进停用词表,再跑 LDA,主题质量会明显提升。

4.4 关联规则全是伪相关:没做时间窗口约束

现象是跑出“可乐 + 儿童套餐”这种提升度很高的组合,但实际是两拨不同客群。原因是没区分订单场景。解决办法是按就餐时段、客群标签分群后再跑关联,或者加入时间窗口,只统计同一订单内的共现,别把跨订单的也混进去。

4.5 评估口径不一致:优化前后数据不可比

现象是菜单调整后销售额涨了,但说不清是菜单的功劳还是季节因素。原因是前后对比没控制变量。解决办法是固定对比窗口(比如调整前后各 4 周)、固定客群(只对比会员复购)、固定渠道(只对比堂食或只对比外卖),把能控制的变量都控制住,剩下的差异才归因到菜单。

5. 从分析结果到菜单动作:把结论翻译成可执行的调整

5.1 情感结果怎么变成保留/改进/淘汰清单

情感分析跑完你会得到每个菜品的正向率和负向率。我的做法是画一张四象限图:横轴是销量,纵轴是正向率。高销量高正向的菜是招牌,必须保留并放在菜单黄金位;高销量低正向的菜是“流量但口碑差”,优先改进配方或出餐流程;低销量高正向的菜是“潜力股”,值得加大推荐权重;低销量低正向的菜直接淘汰。文档里说的保留推广、改进淘汰,落到操作就是这张图。

5.2 主题结果怎么指导新品方向

主题挖掘出的高频负面主题就是新品机会。比如“分量小”反复出现,你可以推加大份版本或加量不加价的套餐;“等太久”反复出现,说明出餐流程有问题,这不是菜单能解决的,但你可以通过预制半成品缩短出餐时间。正面主题则用来强化,比如“汤底浓”被反复夸,就把它做成系列,衍生出不同口味的汤底菜品。

5.3 关联结果怎么设计套餐和推荐顺序

关联规则跑出的高提升度组合,直接拿来做套餐。比如“酸菜鱼 + 米饭 + 酸梅汤”提升度 1.8,就把它打包成一个套餐,定价比单点总和低 10% 到 15%,既提客单价又提满意度。推荐顺序上,把高关联菜品在菜单上放相邻位置,或者在点餐系统里做“猜你喜欢”的联动推荐,转化率比随机推荐高不少。

5.4 成本与利润的平衡:别只看满意度

文档专门用一节讲成本与利润平衡,这点很关键。有些菜满意度高但食材成本也高,毛利率低,全保留会拖垮利润;有些菜满意度一般但成本极低,是利润奶牛。我的做法是给每个菜算一个“满意度/毛利率”比值,比值高的优先保留,比值低的要么改配方降成本,要么淘汰。菜单优化不是纯数据问题,是数据和财务的联合决策。

# 菜品综合评分:满意度权重 0.6,毛利率权重 0.4 data['score'] = data['positive_rate'] * 0.6 + data['gross_margin'] * 0.4 menu_rank = data.sort_values('score', ascending=False) print(menu_rank[['dish_name', 'positive_rate', 'gross_margin', 'score']].head(20))

权重 0.6 和 0.4 不是固定的,取决于你的经营阶段:新店拉口碑可以满意度权重高些,成熟店保利润可以毛利率权重高些。这个公式的价值在于把两个维度的决策变成一个可排序的分数,避免开会时各说各话。

6. 验证与迭代:怎么确认菜单调整真的有效

菜单改完不是结束,是验证的开始。我一般会做三组对比:调整前 4 周 vs 调整后 4 周的整体销售额和客单价;被保留菜品 vs 被淘汰菜品的销量迁移;新套餐 vs 原有单点的转化率。这三组数据跑出来,才能说清楚调整到底有没有用、用在哪。

import pandas as pd # 前后对比:按周聚合,看趋势而不是单点 before = pd.read_csv('sales_before.csv') after = pd.read_csv('sales_after.csv') before_weekly = before.groupby('week')['revenue'].sum() after_weekly = after.groupby('week')['revenue'].sum() print('调整前周均:', before_weekly.mean()) print('调整后周均:', after_weekly.mean()) print('变化幅度:', (after_weekly.mean() - before_weekly.mean()) / before_weekly.mean())

看趋势别只看均值,均值会被极端周拉偏。我习惯把周序列画出来,看调整后是持续上升还是只涨了一周就回落。如果只涨一周,大概率是新鲜感,不是菜单结构真的优化了。另外一定要留一个对照组,比如同期没调整的门店,不然季节因素根本排除不掉。

从那以后我每次做菜单优化,都强制走一遍“采集-清洗-情感-主题-关联-验证”这六步,哪怕数据量只有几千条也不跳步,因为跳过任何一步,后面得出的结论都可能是玄学。这份 26 页的 PDF 最大的价值不是给了多少代码,而是把这条链路的每一步都摆出来了,你可以照着搭自己的版本。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询