☰
旅游景点评论数据分析实战:从数据清洗到差评挖掘的完整方案
2026/11/6 2:21:21 网站建设 项目流程

简介:这份资源面向希望入门数据分析实战的初学者与旅游行业从业者,以去哪儿网国庆景点数据为样本,完整演示从数据清洗到可视化呈现的分析流程,帮助读者掌握用Python处理真实业务数据的思路与方法。压缩包共7个文件,约79KB,包含5个html可视化页面、1个xlsx原始数据表和1个py分析脚本,分别对应图表成果展示、数据源存储与预处理分析代码,结构紧凑、开箱即用。目前已有1387人学习下载。读者可从中获得各省份景点分布热力图、门票销售额TOP20柱状图、景区星级比例饼图等多类图表的实现参考,以及基于Pandas、NumPy、Matplotlib的数据清洗与时间序列分析脚本,便于对照复现热门景点排行与业务洞察,快速积累一份可写入简历的完整分析案例。

1. 从一份“景点评论表”说起:这套分析方案到底解决什么问题

手里拿到一份旅游景点的评论数据,字段大概就是景点名称、评分、评论内容、评论时间、所在城市这么几列,很多人第一反应是画个评分分布直方图、算个平均分就交差了。但真正做过完整项目的人都知道,这种交付物在答辩现场撑不过三个追问:哪个景点被高估了?差评集中在什么问题上?旺季和淡季的口碑差异有多大?这套旅游景点数据分析方案,就是围绕这三个问题搭起来的,目标读者是正在做数据分析毕设、课设,或者要给业务方交一份景点口碑分析报告的人。它不追求模型多花哨,重点在于把“数据清洗—指标设计—多维分析—结论输出”这条链路走完整,让每一张图都能回答一个具体问题。

2. 需求拆解与数据准备:先把问题定义清楚再动手

2.1 三类核心问题与对应指标

动手写代码之前,我一般会先把模糊的“分析一下景点”翻译成可计算的指标。这个项目里,需求最终收敛成三组问题,每组对应一组指标:

业务问题对应指标计算口径
哪些景点口碑好但热度低,值得推荐平均评分、评论量、评分中位数按景点分组聚合,剔除评论数少于阈值的样本
差评到底在骂什么差评率、差评关键词频次评分≤2 视为差评,对评论文本分词后统计高频词
口碑有没有季节性月度平均评分、月度评论量按评论时间提取年月后分组

这里有个容易被忽略的点:平均评分和评分中位数要一起看。有些景点平均分被少量五星评论拉高,中位数却明显偏低,这种“虚高”恰恰是分析报告里最有价值的发现。评论数阈值通常设成 30 条,低于这个数的景点统计意义太弱,直接进结论会翻车。

2.2 数据清洗的四个固定动作

原始评论数据几乎没有拿来就能用的,我一般固定做四件事,顺序不能乱:

import pandas as pd import re df = pd.read_csv("scenic_comments.csv") # 1. 字段类型规整:评分转数值,时间转 datetime,无法转换的置空 df["score"] = pd.to_numeric(df["score"], errors="coerce") df["comment_time"] = pd.to_datetime(df["comment_time"], errors="coerce") # 2. 去重:同一用户对同一景点同一时间的重复评论只保留一条 df = df.drop_duplicates(subset=["scenic_name", "user_id", "comment_time"]) # 3. 缺失处理:评分或景点名缺失的记录直接丢弃,评论内容缺失保留但标记 df = df.dropna(subset=["scenic_name", "score"]) df["content_missing"] = df["content"].isna() # 4. 异常值过滤:评分限定在 1-5,时间限定在合理区间 df = df[(df["score"] >= 1) & (df["score"] <= 5)] df = df[df["comment_time"].dt.year.between(2018, 2025)]

这段代码的关键不在语法,而在每一步的判断依据。去重用的三个字段组合,是因为同一用户可能在不同时间对同一景点多次评论,那是真实行为不能删;缺失处理里评论内容缺失不直接丢行,是因为评分本身仍有分析价值,只是文本分析时要单独排除;时间区间过滤是为了剔除明显录入错误的年份,比如 1900 年这种脏数据。参数上,评分范围和时间范围要按实际数据分布调整,不要照抄。

2.3 文本字段的预处理

评论内容是这套分析里信息密度最高的字段,但也是最脏的。预处理分三步:去掉表情符号和特殊字符、按标点切分短句、过滤掉“的、了、很、非常”这类无信息量的词。中文分词通常用 jieba,停用词表用通用表加一份旅游领域补充词(比如“景点”“门票”“排队”这类词在差评分析里要保留,在主题聚类里可能要降权)。这一步做完,才能进入后面的关键词统计。

3. 分析模块设计:从描述统计到文本挖掘的四层结构

3.1 第一层:景点维度的描述统计

这一层解决“整体长什么样”。按景点分组,算出评论量、平均分、中位数、标准差、差评率,输出一张景点画像表。标准差这个指标很多人不加,但它能区分“口碑稳定”和“褒贬不一”——两个景点平均分都是 4.0,一个标准差 0.3,一个标准差 1.2,后者说明体验波动大,对游客的决策参考价值完全不同。

summary = df.groupby("scenic_name").agg( comment_count=("score", "size"), avg_score=("score", "mean"), median_score=("score", "median"), std_score=("score", "std"), bad_rate=("score", lambda s: (s <= 2).mean()) ).reset_index() # 只保留样本量足够的景点,避免小样本误导 summary = summary[summary["comment_count"] >= 30] summary = summary.sort_values("avg_score", ascending=False)

聚合之后按平均分排序只是第一步,真正有用的是把“平均分高但评论量低”和“平均分中等但评论量高”的景点分开看,前者是潜力推荐位,后者是流量担当但口碑有隐患。这个交叉判断通常用散点图呈现,横轴评论量、纵轴平均分,一眼就能分出四个象限。

3.2 第二层:时间维度的趋势分析

时间维度要回答的是“什么时候去体验最好、什么时候差评最多”。做法是按年月分组,算月度平均分和月度评论量,两条曲线叠在一张图上。这里有个细节:评论量和评分往往负相关——旺季人多,评论量涨,平均分反而跌。这个规律如果数据里存在,就是报告里很扎实的一个结论;如果不存在,也要如实写出来,不能为了故事性硬编。

df["year_month"] = df["comment_time"].dt.to_period("M") monthly = df.groupby("year_month").agg( avg_score=("score", "mean"), comment_count=("score", "size") ).reset_index() monthly["year_month"] = monthly["year_month"].astype(str)

参数上,按月分组在数据量小时会显得稀疏,可以退到按季度;数据量大时按周也可以。判断标准是每个时间桶里至少有 20 条评论,否则曲线抖动全是噪声。

3.3 第三层:差评文本的关键词挖掘

差评分析是这套方案的重头戏。做法是把评分≤2 的评论单独抽出来,分词后统计词频,取前 20 个高频词做词云或条形图。但只做词频是不够的,因为“排队”“门票”“厕所”这些词本身不带情感,要结合上下文才能判断是抱怨还是陈述。我一般的处理是:先按词频筛出候选词,再人工过一遍,把明显中性的词剔掉,剩下的才是真正的“痛点词”。

import jieba from collections import Counter bad_comments = df[df["score"] <= 2]["content"].dropna() words = [] for text in bad_comments: words.extend([w for w in jieba.cut(text) if len(w) >= 2]) # 停用词表需自行维护,这里只做示意 stopwords = {"景点", "感觉", "真的", "一个", "没有"} counter = Counter([w for w in words if w not in stopwords]) top_words = counter.most_common(20)

这段代码里len(w) >= 2是过滤单字噪声,停用词表要按实际语料补充。词频统计完之后,通常还会做一步共现分析——比如“排队”和“门票”经常一起出现,说明问题出在购票环节的排队,而不是景区内的游览排队,这个区分对提改进建议很关键。

3.4 第四层:结论输出与可视化组织

分析结果最终要落到一份能读的报告上。我的习惯是每张图配一句结论,图是证据,结论是观点,两者缺一不可。可视化工具用 matplotlib 或 pyecharts 都行,关键是图的形式要匹配问题:分布用直方图、对比用条形图、趋势用折线图、象限判断用散点图。不要为了好看堆一堆花哨图表,答辩时老师问“这张图说明什么”答不上来,比图丑更致命。

4. 实现细节与工程组织:让分析脚本能复跑、能改

4.1 目录结构与模块划分

一个人写分析脚本容易写成一个大文件从头跑到尾,但这份方案是要交付的,结构得立住。我一般按下面这样分:

project/ ├── data/ │ ├── raw/ # 原始数据,只读不改 │ └── processed/ # 清洗后的中间数据 ├── src/ │ ├── clean.py # 清洗逻辑 │ ├── analyze.py # 统计与文本分析 │ └── visualize.py # 图表生成 ├── output/ │ ├── figures/ # 图表 │ └── report.md # 结论汇总 └── requirements.txt

这样分的好处是清洗逻辑和展示逻辑解耦,数据换了只需要重跑 clean.py,图表样式要调只动 visualize.py。requirements.txt 里锁定 pandas、jieba、matplotlib 的版本,避免换台机器跑不起来——这是很多人答辩前夜踩的坑。

4.2 关键参数的外置管理

分析里有一堆阈值:评论数下限、差评分数线、时间范围、高频词数量。这些不要硬编码在函数里,统一放到一个配置字典或 config 文件里:

CONFIG = { "min_comment_count": 30, # 景点最少评论数 "bad_score_threshold": 2, # 差评分数线 "year_range": (2018, 2025), "top_word_num": 20 }

外置之后,答辩时老师问“如果把差评标准改成 3 分结果会怎样”,你改一个数字重跑就行,不用翻代码找地方。这个习惯看着小,实际是工程素养的体现。

4.3 结果的可复现性保障

可复现的意思是:同样的原始数据,任何人跑一遍都得到同样的图和同样的数字。要做到这点,除了固定随机种子(如果用了聚类或采样),还要保证分组聚合的排序稳定、时间解析不依赖本地时区。文本分析里如果用了词向量或主题模型,随机性更强,通常会在报告里注明“结果受随机种子影响,趋势一致但具体数值可能有小幅波动”,这句话写上去反而显得专业。

5. 避坑与常见问题:这几处翻车点我基本每次都遇到

5.1 平均分被小样本拉偏

现象:某个只有 5 条评论的景点平均分 5.0,排到了推荐榜第一。原因是没有设评论数下限,小样本的统计波动被当成了真实信号。解决办法就是前面说的阈值过滤,评论数低于 30 的景点单独列一张“样本不足”表,不参与排名,但保留展示。

5.2 时间字段解析失败导致趋势图断裂

现象:月度趋势图中间缺了几个月,或者所有数据挤在一个点上。原因通常是原始时间格式不统一,有的是“2023-05-01”,有的是“2023/5/1”,pd.to_datetime默认解析不了混合格式。解决办法是显式指定format="mixed"或先做格式归一化,解析失败的行单独统计数量,数量大就说明数据源有问题,得回头找数据提供方确认。

5.3 差评关键词全是中性词

现象:词频前二十里一半是“门票”“景区”“时间”这种词,看不出痛点。原因是没做停用词和词性过滤,名词性中性词占了主导。解决办法是结合词性标注只保留形容词和动词性词汇,或者用 TF-IDF 而不是纯词频,把在各景点评论里都高频出现的通用词权重压下去。

5.4 图表结论和数字对不上

现象:报告里写“A 景点口碑最好”,但表格里 B 景点的平均分更高。原因多半是排名用了过滤前的数据,结论引用的是过滤后的数据,两套口径混用。解决办法是所有结论只从同一张最终汇总表里取数,图表和文字引用同一个变量,不要手抄数字。

5.5 中文乱码

现象:图表里的中文全变成方框。原因是 matplotlib 默认字体不支持中文。解决办法是在 visualize.py 开头统一设置plt.rcParams["font.sans-serif"] = ["SimHei"]并关闭负号显示问题,这一行漏了,前面分析做得再好,图一出来就露怯。

6. 验收与答辩:怎么证明这套分析是站得住的

验收这套方案,我一般按“数据—指标—结论—建议”四层逐层过。第一层看数据:原始数据多少条、清洗后剩多少条、丢弃比例是多少、丢弃原因分布如何,这几个数字要能一口报出来,说明你对数据有掌控。第二层看指标:每个指标的计算口径能不能用一句话说清,比如“差评率是评分≤2 的评论占该景点总评论数的比例”,口径含糊的指标直接砍掉。第三层看结论:每条结论背后有没有对应的图表支撑,结论和图表数字是否一致,这一层最容易出问题,建议做一张“结论—图表—数据来源”的对照表自查。第四层看建议:分析得出的痛点有没有落到可执行的改进方向上,比如差评集中在排队,建议就写分流或预约制,而不是泛泛说“提升服务质量”。

答辩现场有几个高频追问,提前准备好答案能省很多事。一是“为什么用平均分不用中位数”,答两者都看、中位数抗极端值、平均分反映整体感受,组合使用。二是“差评阈值为什么是 2 不是 3”,答按数据分布定的,可以现场演示改成 3 之后差评率的变化趋势是否一致,一致说明结论稳健。三是“文本分析为什么不用深度学习模型”,答这个数据量和分析目标下,词频加人工校验的性价比最高,模型复杂度要匹配问题复杂度,硬上模型反而不好解释。这三问答顺了,基本就稳了。

还有一个具体技巧:答辩前把整个流程从原始数据到最终图表完整跑一遍,掐表记录耗时,确保演示时不会卡在环境问题上。我吃过一次亏,现场网络不通装不了依赖,最后靠提前导出的中间结果救场。从那以后我每次交付分析项目,都会把清洗后的数据和关键图表提前导出到本地,演示只读本地文件,不依赖现场环境。希望这套结构能帮到你,把手里那份景点数据真正讲出一个有依据的故事。

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

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

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

立即咨询