Python旅游推荐数据分析可视化:毕业设计完整链路与避坑指南
发布时间:2026/10/1 14:55:41来源:尧图网络
简介这份资源是面向计算机相关专业毕设学生与Python项目实战学习者的旅游推荐数据分析可视化系统采用PythonDjangoMySQL技术栈并引入协同过滤算法实现个性化推荐可直接作为毕业设计、课程设计或期末大作业使用。压缩包共422个文件约9.36MB以174个js、59个css、40个json、27个py、18个html等为主涵盖前端页面样式、后端业务逻辑、数据配置与模板渲染另附sql数据库脚本、docx部署说明及md文档便于快速搭建运行环境。系统功能完整用户端支持登录注册、个人信息管理、景区浏览、评分收藏与智能推荐管理员端可对景区信息及类型进行分类管理并查看和维护用户资料与行为记录。项目经过严格调试确保可运行已有82人学习下载适合需要完整赛题方案、清晰目录结构与排错思路的读者参考实践。1. 旅游推荐数据分析可视化从一份毕业设计源码到能跑起来的完整链路很多同学拿到「基于 Python 的旅游推荐数据分析可视化」这个题目时第一反应是去搜免费 Python 源码大全下载一个压缩包解压然后发现跑不起来——缺库、缺数据、路径写死、编码报错最后只能对着别人的截图改改论文。这个标题真正要解决的问题不是「推荐算法有多深」而是把数据采集、清洗、推荐计算、可视化展示串成一条能在本地复现的链路。它适合两类人一是正在做计算机毕业设计、需要一套可演示可答辩系统的同学二是想用 Python 数据分析与可视化练手、但不想从零造轮子的初学者。核心词就三个Python、旅游推荐、数据分析可视化。下面按「数据怎么来、推荐怎么算、图怎么画、坑怎么躲」的顺序拆开讲每一步都给出可抄的代码和参数说明。2. 数据从哪来旅游数据集的获取、清洗与字段设计2.1 三种常见数据来源与选型理由旅游推荐系统的数据通常分三块景点/酒店/餐厅的基础信息、用户行为数据评分、浏览、收藏、以及评论文本。毕业设计场景下最稳的做法是用公开数据集打底再补少量爬虫数据。常见做法是公开数据集如景区评分、酒店评论类 CSV字段规整适合直接进推荐流程。爬虫补充用 requests BeautifulSoup 抓取景点名称、评分、地址、简介注意控制频率别把人家站点抓崩。模拟用户行为自己用脚本生成 user_id、item_id、rating 三列方便演示协同过滤。选型理由很直接公开数据集保证字段完整爬虫补充保证数据量够画图模拟行为保证推荐算法有输入。三者拼起来系统才像那么回事。2.2 清洗脚本去重、缺失值、类型转换拿到数据后第一件事不是画图是清洗。下面这段脚本处理景点表逻辑是读 CSV → 去重 → 填充缺失评分 → 统一城市字段 → 输出干净文件。import pandas as pd import numpy as np # 读取原始景点数据注意 encoding 参数中文数据常见 gbk 或 utf-8-sig df pd.read_csv(raw_spots.csv, encodingutf-8-sig) # 1. 按景点名称去重保留第一条 df df.drop_duplicates(subset[spot_name], keepfirst) # 2. 评分缺失用中位数填充避免均值被极端值拉偏 df[score] df[score].fillna(df[score].median()) # 3. 城市字段统一去掉空格并转成字符串 df[city] df[city].astype(str).str.strip() # 4. 价格字段转数值无法转换的置为 NaN 后删除 df[price] pd.to_numeric(df[price], errorscoerce) df df.dropna(subset[price]) # 5. 输出清洗后数据 df.to_csv(clean_spots.csv, indexFalse, encodingutf-8-sig) print(清洗完成剩余记录数, len(df))参数说明encodingutf-8-sig是为了兼容 Excel 打开时不乱码errorscoerce把无法转数值的脏数据变成 NaN再统一删掉keepfirst表示重复项只留第一条。失败时先看列名是否和脚本一致再看编码最后看有没有空文件。2.3 用户行为表的设计与生成推荐算法需要用户-物品交互矩阵。毕业设计里如果没有真实用户数据可以用脚本模拟。下面生成 200 个用户对 50 个景点的评分评分范围 1 到 5。import pandas as pd import numpy as np np.random.seed(42) # 固定随机种子保证每次生成结果一致 user_ids [fU{i:03d} for i in range(1, 201)] spot_ids [fS{i:03d} for i in range(1, 51)] records [] for u in user_ids: # 每个用户随机选 10 到 30 个景点评分 n np.random.randint(10, 31) chosen np.random.choice(spot_ids, sizen, replaceFalse) for s in chosen: records.append([u, s, np.random.randint(1, 6)]) behavior pd.DataFrame(records, columns[user_id, spot_id, rating]) behavior.to_csv(user_behavior.csv, indexFalse, encodingutf-8-sig) print(behavior.head())这段代码的关键参数是np.random.seed(42)固定种子后每次跑出来的数据一样方便调试和写论文截图。replaceFalse保证一个用户不会对同一个景点重复评分。生成后可以用behavior.describe()看评分分布如果全是 3 分说明随机范围有问题。3. 推荐算法怎么选协同过滤与基于内容的落地对比3.1 协同过滤用户相似度计算与推荐生成协同过滤的核心是「相似的人喜欢相似的东西」。用 pandas 构建用户-景点评分矩阵再算用户余弦相似度最后给目标用户推荐他没看过但相似用户高分的景点。import pandas as pd from sklearn.metrics.pairwise import cosine_similarity behavior pd.read_csv(user_behavior.csv) # 构建用户-景点评分矩阵缺失值填 0 matrix behavior.pivot_table(indexuser_id, columnsspot_id, valuesrating).fillna(0) # 计算用户之间的余弦相似度 user_sim cosine_similarity(matrix) user_sim_df pd.DataFrame(user_sim, indexmatrix.index, columnsmatrix.index) def recommend(user_id, top_n5): # 取该用户与其他用户的相似度排除自己 sim_scores user_sim_df[user_id].drop(user_id) # 取最相似的 10 个用户 similar_users sim_scores.sort_values(ascendingFalse).head(10).index # 找这些相似用户评分高、但目标用户没评分的景点 candidate behavior[behavior[user_id].isin(similar_users)] candidate candidate[~candidate[spot_id].isin( behavior[behavior[user_id] user_id][spot_id])] # 按平均评分排序 rec candidate.groupby(spot_id)[rating].mean().sort_values(ascendingFalse).head(top_n) return rec print(recommend(U001))参数说明fillna(0)表示未评分视为 0 分这是协同过滤的常见处理head(10)控制相似用户数量太大引入噪声太小推荐不准top_n5是最终推荐个数。如果推荐结果为空说明该用户已经评过所有候选景点或者相似用户太少可以调大相似用户数量。3.2 基于内容的推荐用景点标签做相似度协同过滤有冷启动问题——新用户没评分就推不了。这时候用基于内容的推荐兜底把景点名称、城市、标签拼成文本用 TF-IDF 向量化再算景点之间的相似度。from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import linear_kernel spots pd.read_csv(clean_spots.csv) # 把城市和标签拼成特征文本 spots[content] spots[city].astype(str) spots[tags].astype(str) tfidf TfidfVectorizer(stop_wordsNone) tfidf_matrix tfidf.fit_transform(spots[content]) # 计算景点之间的余弦相似度 cosine_sim linear_kernel(tfidf_matrix, tfidf_matrix) def content_recommend(spot_name, top_n5): idx spots[spots[spot_name] spot_name].index[0] sim_scores list(enumerate(cosine_sim[idx])) sim_scores sorted(sim_scores, keylambda x: x[1], reverseTrue) sim_scores sim_scores[1:top_n1] spot_indices [i[0] for i in sim_scores] return spots[spot_name].iloc[spot_indices] print(content_recommend(西湖))这里TfidfVectorizer把文本转成向量linear_kernel算相似度比 cosine_similarity 更快。注意stop_wordsNone是因为中文停用词需要自己准备毕业设计里不处理也能跑。如果报错说某个景点找不到先检查名称是否有多余空格。3.3 两种算法的融合与切换策略实际系统里不会只用一种。常见做法是用户有评分记录时走协同过滤没有时走基于内容。下面这个判断逻辑可以直接用。def hybrid_recommend(user_id, spot_nameNone, top_n5): user_records behavior[behavior[user_id] user_id] if len(user_records) 5: return recommend(user_id, top_n) elif spot_name: return content_recommend(spot_name, top_n) else: # 兜底返回评分最高的热门景点 return behavior.groupby(spot_id)[rating].mean().sort_values(ascendingFalse).head(top_n) print(hybrid_recommend(U001, 西湖))阈值 5是经验值评分少于 5 条时协同过滤不稳定。这个融合策略在答辩时很好讲既解决了冷启动又保留了协同过滤的个性化。4. 可视化怎么做从 ECharts 大屏到 Python 静态图4.1 用 Pyecharts 生成可交互的 HTML 图表毕业设计演示时静态图不如可交互图表有冲击力。Pyecharts 能直接输出 HTML浏览器打开就能点。下面画一个景点评分分布柱状图。from pyecharts.charts import Bar from pyecharts import options as opts import pandas as pd spots pd.read_csv(clean_spots.csv) # 按城市统计平均评分 city_score spots.groupby(city)[score].mean().sort_values(ascendingFalse).head(10) bar ( Bar() .add_xaxis(city_score.index.tolist()) .add_yaxis(平均评分, city_score.values.round(2).tolist()) .set_global_opts( title_optsopts.TitleOpts(title城市景点平均评分 Top10), xaxis_optsopts.AxisOpts(name城市), yaxis_optsopts.AxisOpts(name评分), ) ) bar.render(city_score.html) print(图表已生成city_score.html)参数说明head(10)只取前 10 个城市避免横轴太挤round(2)保留两位小数render输出 HTML 文件。如果中文显示乱码在set_global_opts里加title_opts的字体设置或者检查 HTML 的 meta 编码。4.2 用 Matplotlib 画推荐结果对比图论文里通常需要静态图。下面画协同过滤和基于内容推荐的评分对比。import matplotlib.pyplot as plt import pandas as pd # 假设已有两种算法的推荐结果 cf_rec recommend(U001, top_n5) content_rec content_recommend(西湖, top_n5) fig, axes plt.subplots(1, 2, figsize(12, 5)) axes[0].barh(cf_rec.index, cf_rec.values, color#4C72B0) axes[0].set_title(协同过滤推荐评分) axes[0].set_xlabel(预测评分) axes[1].barh(content_rec.index, [1]*len(content_rec), color#DD8452) axes[1].set_title(基于内容推荐景点) axes[1].set_xlabel(相似度) plt.tight_layout() plt.savefig(recommend_compare.png, dpi150) print(对比图已保存)figsize(12,5)控制画布大小dpi150保证论文打印清晰。barh是横向柱状图适合景点名称较长的情况。如果保存的图空白检查plt.show()是否在savefig之前调用了。4.3 可视化大屏的布局思路与数据接口如果要做可视化大屏常见结构是顶部标题栏、左侧城市筛选、中间地图或柱状图、右侧推荐列表。数据接口可以用 Flask 暴露 JSON前端用 ECharts 异步加载。from flask import Flask, jsonify import pandas as pd app Flask(__name__) app.route(/api/city_score) def city_score(): spots pd.read_csv(clean_spots.csv) data spots.groupby(city)[score].mean().round(2).to_dict() return jsonify(data) if __name__ __main__: app.run(debugTrue, port5000)port5000是 Flask 默认端口debugTrue方便改代码自动重启。前端用fetch(/api/city_score)拿数据后传给 ECharts 的setOption。注意跨域问题本地开发可以在 Flask 加 CORS 头或者前端和后台同端口部署。5. 避坑与排查毕业设计里最容易翻车的 5 个地方5.1 编码报错UnicodeDecodeError现象读 CSV 时抛UnicodeDecodeError: utf-8 codec cant decode byte。原因原始文件是 GBK 编码脚本用 UTF-8 读。解决先试encodinggbk再试encodingutf-8-sig或者用chardet检测编码。5.2 路径写死换台电脑就跑不了现象代码里写C:/Users/xxx/Desktop/data.csv换电脑后 FileNotFoundError。原因绝对路径依赖本机目录。解决统一用相对路径把数据文件和脚本放同一目录或者用os.path.dirname(__file__)拼路径。5.3 库版本冲突sklearn 报错 API 变了现象ImportError: cannot import name cosine_similarity或参数名变了。原因不同版本 sklearn 接口有差异。解决在requirements.txt里锁定版本比如scikit-learn1.3.0部署时用pip install -r requirements.txt。5.4 推荐结果为空冷启动没处理现象新用户调用recommend返回空列表。原因该用户没有评分记录协同过滤算不出相似用户。解决加融合逻辑没记录时走基于内容或热门兜底参考 3.3 节的hybrid_recommend。5.5 可视化中文乱码Matplotlib 显示方块现象图表里中文变成方框。原因Matplotlib 默认字体不支持中文。解决在画图前加两行配置。import matplotlib matplotlib.rcParams[font.sans-serif] [SimHei] matplotlib.rcParams[axes.unicode_minus] FalseSimHei是 Windows 自带黑体Mac 可以换Arial Unicode MS。axes.unicode_minusFalse解决负号显示异常。6. 让系统更像一个产品部署、答辩演示与可扩展方向把代码跑通只是第一步答辩时老师会问「你怎么部署的」「能不能现场演示」。我一般会准备一个requirements.txt和一个启动脚本确保换电脑也能三行命令跑起来。# 1. 创建虚拟环境 python -m venv venv # 2. 激活环境Windows venv\Scripts\activate # 3. 安装依赖 pip install -r requirements.txt # 4. 启动 Flask 服务 python app.pyrequirements.txt里至少写pandas、numpy、scikit-learn、pyecharts、flask、matplotlib。版本号建议锁定避免答辩当天装不上。演示顺序也有讲究先打开可视化大屏展示数据概览再输入一个用户 ID 展示推荐结果最后打开代码讲清洗和算法逻辑。这样老师能看到「数据→算法→展示」的完整闭环。可扩展方向有三个一是把推荐结果存进 Redis加快重复查询二是用大模型智能体做旅游推荐对话把推荐结果转成自然语言三是把可视化大屏换成 Vue ECharts 前后端分离更像企业项目。但毕业设计时间有限先把当前链路跑稳再挑一个方向做深。我自己踩过最深的坑是数据清洗没做干净导致推荐结果全是同一个景点答辩时被问「为什么推荐这么集中」当场翻车。后来养成习惯每次跑完推荐先看结果分布如果 Top5 全是同一个城市就回去查数据。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网