Python旅游推荐数据分析可视化:从数据清洗到协同过滤全流程实战
简介这是一套基于Python、Django与MySQL的旅游推荐数据分析可视化项目专为计算机相关专业毕业设计、课程设计及期末大作业设计同时适合需要项目实战的Python学习者。项目内置协同过滤推荐算法实现用户登录注册、个人信息管理、景区浏览、评分收藏与个性化推荐管理员端则支持景区信息维护、类型分类管理以及用户资料和行为记录的查看与修改功能覆盖完整。压缩包共422个文件大小9.36MB包含Python后端源码、Django配置文件、前端js/css/html页面、数据库SQL脚本以及部署说明文档csv与json数据文件可用于数据分析可视化演示目录结构清晰便于按需查找和二次开发。目前已有135人学习关注。资源附带可直接运行的源码和数据库文件并配有部署说明能帮助学习者快速搭建环境、理解推荐算法与Django框架的落地流程同时节省环境配置和调试的时间适合需要完整项目方案的学生直接参考使用。1. 旅游推荐数据分析可视化这份源码包能带你走通什么假设你刚下载了一份“python项目实战之旅游推荐数据分析可视化”的压缩包里面是Python脚本、样例数据和一份部署说明。你大概率是三种人之一正在做课程设计或毕业设计的学生需要在业务里验证旅游产品推荐方案的从业者或者想找一个完整数据分析项目练手的开发者。这个项目解决的是整条链路的问题——把景点评分、订单记录和用户行为数据清洗干净算出“该给谁推荐什么”最后用可视化把结论摆到一张能汇报的图上。它适合手里有数据但不知道从哪下手的初学者也适合想快速复现全流程的在职工程师。接下来六章我按选型、清洗、可视化、避坑、部署的顺序把这份源码讲成一篇能照着复现的实战笔记。2. 先从源码理解项目技术选型、目录结构与数据链路2.1 旅游推荐的数据链路从订单明细到用户偏好画像拿到一份源码包最忌讳的是什么都还没看就python main.py跑起来就以为完事了。我一般会先花十分钟把数据链路盘清楚这个项目的输入是什么中间算了什么输出又是什么。旅游推荐项目里的原始数据逃不出三张表——users.csv 存用户ID和常住城市spots.csv 存景点ID、城市、类别、门票价格orders.csv 是核心记录每次订单的 user_id、spot_id、rating 评分、amount 消费金额和 order_date 下单日期。推荐和分析的所有逻辑都是从这三张表聚合出来的。先写一段装载代码确认数据规模再动手import pandas as pd users pd.read_csv(data/users.csv) spots pd.read_csv(data/spots.csv, encodingutf-8) orders pd.read_csv(data/orders.csv, parse_dates[order_date]) for name, df in [(users, users), (spots, spots), (orders, orders)]: print(f{name}: {df.shape}, 缺失值: {df.isnull().sum().sum()})这里有两个参数值得停下来解释。encodingutf-8是针对含中文的景点表如果文件实际是 GBK 编码保存的就要改成encodinggbk或encodingutf-8-sig否则读进来就是一堆乱码parse_dates[order_date]把日期列解析成 datetime 类型后面做月度聚合、季节性分析才转得动。打印出来的 shape 和缺失值总数是判断清洗工作量的第一手依据。三张表盘完下一步是合成一张宽表方便后面同时按用户和景点两个维度做聚合。常见做法是拿订单表做主表做 left joinwide_df (orders .merge(users, onuser_id, howleft) .merge(spots, onspot_id, howleft)) print(wide_df.head()) print(wide_df.dtypes)howleft的意思是保留 orders 中的全部订单用户表或景点表里缺失的字段自动补 NaN不会因为外键对不上把订单丢掉。这一步做完数据链路的中间产物就齐了。数据链路用一句话概括订单表为主表join 出宽表之后兵分两路。一路按 user_id 聚合出用户偏好画像——人均消费、平均评分、去过哪些城市、偏好什么景点类别另一路按 spot_id 聚合出景点热度画像——评分均值、订单量、好评率。推荐做的就是让这两路画像对上号可视化做的则是把聚合结果用图表摆出来。把这个流向搞清楚后面每个脚本在干什么就不会变成黑匣子。2.2 技术栈选型Pandas、PyECharts、Flask为什么这套组合够用这类项目的定位是数据分析可视化不是生产级推荐系统选型原则是轻、快、好复现。Pandas 处理几十万行订单是舒适区内存和速度都够NumPy 在算余弦相似度这类向量运算时兜底。PyECharts 把图表输出成 HTML 文件浏览器直接打开就能看中文和交互体验比 Matplotlib 省心太多也是做可视化大屏最常见的方案。Flask 负责把几张图表组装成一个页面起一个本地服务。整套组合在单机上就能跑通不需要装数据库也不需要搭大数据集群。很多初学者喜欢把项目往 Spark 上引其实在这个量级纯属给自己加戏。选型理由用一张表对照更清楚环节默认工具选型理由什么时候考虑换数据清洗与特征工程Pandas NumPyAPI 直观单机处理几十万行流畅千万行以上先换 SQL 预聚合再上 Spark图表生成PyECharts输出 HTML浏览器直接看中文支持好论文配图要矢量图时换 Matplotlib页面服务Flask几十行代码串起所有图表需要标准接口文档时换 FastAPI选 PyECharts 还有一个现实原因这个库的版本 API 变化大网上现成的代码大多是 1.x 写法而 pip 默认装的是 2.xfrom pyecharts import Bar和from pyecharts.charts import Bar两种写法混用是新手最常见的翻车点。后面的代码统一用 2.x 的pyecharts.charts加options写法你复制到自己项目里时先确认一下版本。为什么不直接上 BI 工具因为这类项目的核心目标是让人看到“数据是怎么被一步步处理成结论的”代码即过程。BI 拖拽出来的图表虽然快但推荐逻辑和特征计算的黑匣子你解释不清楚。反过来用 Python 全家桶写一遍每一步都能 print 出来验证这才是 python 数据分析与可视化项目实战的意义。2.3 目录结构与部署说明开工前先读哪三个文件源码包解开后通常是这样的结构travel_recommend/ ├── data/ │ ├── users.csv │ ├── spots.csv │ └── orders.csv ├── src/ │ ├── clean.py │ ├── features.py │ ├── recommend.py │ └── visualize.py ├── templates/ │ └── index.html ├── requirements.txt ├── main.py └── 部署说明.md解开 zip 后我建议先读三个文件而不是急着装环境。第一是部署说明里面会写 Python 版本要求和启动方式第二是 requirements.txt确认核心依赖版本尤其是 pyecharts 和 pandas 的版本号第三是 main.py看它是单次生成 HTML 文件还是启动一个常驻的 Flask 服务。这三个文件读明白你对整套代码的定位就清楚了后面部署才不会跑偏。requirements.txt 是排查环境纠纷的第一现场pandas2.0.3 numpy1.24.3 pyecharts2.0.3 flask3.0.0锁版本是有讲究的。pandas 2.x 和 1.x 在 datetime 类型推断上有差异pyecharts 1.x 和 2.x 的 API 直接不兼容。部署说明里如果写了pip install -r requirements.txt千万别图省事只装最新版——项目在 2.0.3 上调通的图表换到 2.1.0 可能就白屏。我见过不少人栽在这个文件上拿到包直接pip install pyecharts装了个最新版代码却按旧版写报错之后开始怀疑人生。先读这三个文件能省下两个小时排错时间。环境问题是所有“源码部署说明”类项目的头号坑后面避坑章还会专门展开。3. 数据清洗与特征工程把旅游数据整理成推荐能用的样子3.1 多源数据读取CSV、Excel、数据库导出的统一装载实际项目中数据源很少只有一份 CSV。景点信息可能来自 Excel 表格订单数据可能是从数据库导出的查询结果用户信息可能是一份 JSON。常见做法是写一个统一的装载函数按后缀自动选读取方式import pandas as pd def load_table(path: str) - pd.DataFrame: 按文件后缀选择读取方式统一返回 DataFrame if path.endswith(.csv): return pd.read_csv(path, encodingutf-8-sig) if path.endswith((.xlsx, .xls)): return pd.read_excel(path) if path.endswith(.json): return pd.read_json(path) raise ValueError(f不支持的文件类型: {path}) orders load_table(data/orders.csv) spots load_table(data/spots.xlsx) users load_table(data/users.json)注意encodingutf-8-sig和utf-8的区别utf-8-sig 会自动吃掉 Excel 或记事本保存时加在文件头部的 BOM 标记省得第一列列名出现看不见的\ufeff前缀。这个坑很隐蔽打印 columns 的时候看不出问题一旦用列名去取数据就报 KeyError。如果订单表是从 MySQL 之类的数据库导出的直接读导出文件就行不用在项目里连数据库——分析项目的原则是数据一次性落地成 CSV后续反复读取避免每次跑代码都依赖数据库连接。如果非要连常见做法是pd.read_sql(sql, engine)但脚本里记得放在if __name__ __main__保护下避免被 import 时误执行。读取完成先print(orders.shape, spots.shape)确认行数和预期一致再往下走。3.2 清洗规则缺失值、重复值、异常日期和价格的四个处理步骤数据装载完清洗围绕四个步骤展开补缺失、去重复、过滤异常值、纠正日期。直接看代码# 1) 评分缺失按同景点平均分填充 spot_mean orders.groupby(spot_id)[rating].transform(mean) orders[rating] orders[rating].fillna(round(spot_mean, 1)) # 2) 重复订单按订单号去重保留第一次下单记录 orders orders.drop_duplicates(subset[order_id], keepfirst) # 3) 异常金额门票区间一般在 20~3000 元越界视为脏数据 orders orders[(orders[amount] 20) (orders[amount] 3000)] # 4) 异常日期只保留 2018-01-01 到 2024-12-31 之间的订单 valid_date (orders[order_date] 2018-01-01) \ (orders[order_date] 2024-12-31) orders orders[valid_date]评分缺失用同景点均值填充是因为同一个景点的评分分布相对稳定比填全局均值更合理。transform(mean)会返回和原表等长的 Series方便直接填充。去重时subset[order_id]只针对订单号判断重复keepfirst保留第一条注意别写成keepFalse那会把重复记录全部删掉包括有效订单。金额过滤用一个业务阈值区间这个阈值需要看数据分布调整——先orders[amount].describe()看分位数再定别照抄。注意不要用fillna(0)填充缺失评分。把没消费过的景点和打了低分的景点混为一谈后面聚合出的平均分会被系统性拉低。日期过滤在分析场景里尤其重要。如果订单表里混着未来日期测试数据或 1970 年之前的脏数据后面做季节性聚合会直接污染月度趋势。最后还要处理数据类型这步容易被忽略# 把金额统一转成 float避免后续计算变成字符串拼接 orders[amount] pd.to_numeric(orders[amount], errorscoerce) # 用户ID和景点ID用 int32 压缩内存 for col in [user_id, spot_id]: orders[col] orders[col].astype(int32)errorscoerce会把无法转成数字的值置为 NaN之后可以再走一遍填充或过滤。转类型同时也在为后面的计算提速——int64 是 pandas 默认整数类型实际数据量不大时int32 能省近一半内存还有利于和推荐矩阵的索引对齐。清洗结束后老规矩打印一次orders.describe()和orders.isnull().sum()确认清洗没有引入新问题。数据这步做得越扎实可视化阶段的返工越少。3.3 特征工程用户打分归一化与景点热度分计算清洗完只是“能看”要做推荐还得构造特征。两个最核心的特征景点的热度分用户对景点的偏好分。景点热度分用三个指标合成——平均评分、订单量、好评率# 景点热度分 0.4 * 平均评分 0.3 * 订单量归一化 0.3 * 好评率 spot_stats orders.groupby(spot_id).agg( avg_rating(rating, mean), order_cnt(order_id, count), good_rate(rating, lambda x: (x 4).mean()), ).reset_index() # 订单量做 min-max 归一化量纲对齐到 0~1 spot_stats[cnt_norm] (spot_stats[order_cnt] - spot_stats[order_cnt].min()) / \ (spot_stats[order_cnt].max() - spot_stats[order_cnt].min()) spot_stats[heat_score] (0.4 * spot_stats[avg_rating] / 5 0.3 * spot_stats[cnt_norm] 0.3 * spot_stats[good_rate])这里有两个细节。第一平均评分除以 5是因为评分是 0~5 分制不做归一化就和另外两项 0~1 的量纲不在一个数量级上加权会失真。第二lambda x: (x 4).mean()直接算好评率布尔求均值就是 True 所占比例。加权系数 0.4/0.3/0.3 是经验值可以按业务重点调整——如果更看重口碑就把 avg_rating 的权重调高。用户偏好画像类似按用户维度聚合user_profile orders.groupby(user_id).agg( avg_spend(amount, mean), avg_rating(rating, mean), visit_cnt(order_id, count), ).reset_index() # 用户打分归一化把个人评分习惯映射到 0~1避免严格评分和宽松评分互相干扰 user_profile[rating_norm] user_profile[avg_rating] / 5用户平均评分除以 5 得到归一化打分是为了在协同过滤里对比不同用户时消除“有人习惯打高分、有人习惯打低分”的口径差异。这两个特征表一个进推荐模块做匹配一个进可视化模块画图是后续所有输出的源头。特征工程这一步做完项目的主体逻辑就成型了一半。4. 可视化落地让分析结论变成能汇报的图表4.1 景点热度Top10与季节性波动柱状图和折线图的配合数据清洗和特征工程做完就到了最能出效果的可视化环节。一份能交差的旅游推荐可视化报告至少要包含三个层次景点热度排行、季节波动、用户画像。PyECharts 就是基于 ECharts 的 Python 封装echarts 数据可视化的交互能力在 HTML 端是现成的。先做最常见的景点热度 Top10from pyecharts.charts import Bar from pyecharts import options as opts top10 spot_stats.sort_values(heat_score, ascendingFalse).head(10) bar ( Bar() .add_xaxis(top10[spot_id].astype(str).tolist()) .add_yaxis(热度分, top10[heat_score].round(3).tolist()) .set_global_opts( title_optsopts.TitleOpts(title景点热度 Top10), xaxis_optsopts.AxisOpts(name景点ID, axislabel_optsopts.LabelOpts(rotate30)), yaxis_optsopts.AxisOpts(name热度分), tooltip_optsopts.TooltipOpts(triggeraxis), ) ) bar.render(output/top10_bar.html)add_xaxis里把景点ID转成 str是为了防止大整数被图表当数字轴处理导致显示错乱。axislabel_optsopts.LabelOpts(rotate30)容易漏——ID 太长默认会重叠成一团黑旋转 30 度之后才看得清。tooltip_opts(triggeraxis)让悬停时按整列显示提示而不是单个数据点。热度排行只反映静态结果旅游数据最有价值的是时间维度。接着做月度订单量趋势和排行配合from pyecharts.charts import Line monthly orders.set_index(order_date)[order_id].resample(M).count() line ( Line() .add_xaxis(monthly.index.strftime(%Y-%m).tolist()) .add_yaxis(月度订单量, monthly.values.tolist()) .set_global_opts( title_optsopts.TitleOpts(title订单量季节性波动), toolbox_optsopts.ToolboxOpts(), ) ) line.render(output/monthly_line.html)resample(M)是 pandas 按月聚合的标准做法M是月末频率用MS是月初。图示的季节性拐点往往是业务方最关心的分析结论——比如寒暑假订单量翻倍也就是推荐系统要重点倾斜的时间窗。如果要把两个图拼在一页常见做法是Page(layoutPage.SimplePageLayout)会把所有图表按顺序排在一张 HTML 里适合交作业或做展示。4.2 用户画像散点图与城市推荐热力图配置要点景点热度之外用户维度也要可视化。散点图最适合展示“消费力 vs 评分倾向”的关系from pyecharts.charts import Scatter scatter ( Scatter() .add_xaxis(user_profile[avg_spend].round(0).tolist()) .add_yaxis(用户, user_profile[rating_norm].round(3).tolist()) .set_global_opts( title_optsopts.TitleOpts(title用户消费金额与评分倾向), xaxis_optsopts.AxisOpts(name人均消费(元), type_value), yaxis_optsopts.AxisOpts(name归一化评分, type_value), ) ) scatter.render(output/user_scatter.html)这里有个 PyECharts 2.x 的细节add_xaxis在散点图上接收的是 X 轴数值序列和柱状图里接收类目序列的语义不一样。很多从柱状图抄过来的人在这里翻车画出来的散点图 X 轴变成了均匀分布的序号。所以 X 轴必须显式声明type_value否则默认按类目轴处理。城市推荐热力图是另一个出效果的点。把“出发城市 x 目的城市”的订单量做成热力图矩阵from pyecharts.charts import HeatMap pivot orders.merge(users, onuser_id, howleft) \ .pivot_table(indexcity, columnsspot_city, valuesorder_id, aggfunccount, fill_value0) x_cities pivot.columns.tolist() y_cities pivot.index.tolist() data [[x, y, int(pivot.loc[y, x])] for y in y_cities for x in x_cities] heatmap ( HeatMap() .add_xaxis(x_cities) .add_yaxis(城市间订单量, y_cities, data) .set_global_opts( title_optsopts.TitleOpts(title出发城市与目的地城市热度矩阵), visualmap_optsopts.VisualMapOpts(max_int(pivot.values.max())), ) ) heatmap.render(output/city_heatmap.html)pivot_table里valuesorder_id加aggfunccount的含义是对每个出发城市目的城市组合统计订单条数这是非常常用的透视写法。HeatMap 的数据格式是[x序号, y序号, 值]的三元组列表数据顺序不对图会直接空白。visualmap_opts的max_控制颜色映射上限不设的话默认到 100数据小的话整张图一个颜色等于白画。这一层的可视化配置本质上是把特征工程的产物翻译成图表参数看懂配置项对应的数据形态比背 API 重要得多。4.3 推荐结果输出协同过滤的简化实现与可视化联动可视化展示的最后一步是把推荐结果也画出来。推荐算法在这个项目里用协同过滤的简化版就够——基于用户的协同过滤找和当前用户打分习惯最像的 k 个用户把他们去过的景点按相似度加权排序import numpy as np from collections import Counter def recommend(user_id, rating_matrix, k5, top_n10): 基于用户的协同过滤简化实现返回推荐的景点ID列表 user_vec rating_matrix.loc[user_id].values sim_scores [] for other_id in rating_matrix.index: if other_id user_id: continue other_vec rating_matrix.loc[other_id].values denom np.linalg.norm(user_vec) * np.linalg.norm(other_vec) if denom 0: continue sim np.dot(user_vec, other_vec) / denom # 余弦相似度 sim_scores.append((other_id, sim)) sim_scores.sort(keylambda x: x[1], reverseTrue) top_users sim_scores[:k] rec_counter Counter() for other_id, sim in top_users: visited rating_matrix.loc[other_id] for spot_id in visited[visited 0].index: rec_counter[spot_id] visited[spot_id] * sim return [sid for sid, _ in rec_counter.most_common(top_n)] rating_matrix orders.pivot_table(indexuser_id, columnsspot_id, valuesrating, fill_value0) rec_result recommend(rating_matrix.index[0], rating_matrix, k5, top_n10) print(推荐结果:, rec_result)这个简化版有三个关键点。第一余弦相似度要先算分母分母为 0 直接跳过否则除零报错。第二visited[visited 0]只取该用户真实去过的景点0 填充的位置不参与推荐否则会把没去过的景点也加权进来。第三返回的是Counter.most_common(top_n)的键如果同一个景点被多个相似用户访问过它的得分会被累加天然完成群体投票。推荐结果最终也要可视化常见做法是把命中的景点 join 回 spots 表拿景点名字和城市画成横向条形图。推荐和展示的联动就是把 recommend() 的返回值塞回之前的绘图表单。这层联动的代码量不大但它是整个项目的临门一脚前面的清洗、特征、可视化都是过程推荐列表才是能直接使用的产品结论。5. 避坑指南旅游数据分析可视化项目里最常见的五个坑这类项目跑通不难难在“换环境就翻车”和“数据稍变就报错”这类边缘情况。下面五个坑按出现频率排每一条都是现象、原因、解决三段式你可以直接对照排查。5.1 中文乱码图表标题变成方块或问号现象PyECharts 生成的 HTML 里图表标题、坐标轴文字中的中文全部变成方块或问号英文正常。原因多数是读取 CSV 时编码没对齐数据里的中文在源头就已经是乱码图表自然跟着乱。另一个来源是用了自定义 HTML 模板模板 head 里缺少meta charsetutf-8浏览器按默认编码解析了中文页面。解决第一步确认原始数据pd.read_csv里显式写encodingutf-8-sig或encodinggbk读进来后print(df.head())目测中文是否正常第二步检查 HTML 模板head 里必须有meta charsetutf-8。这两个地方都对了中文乱码基本消失。5.2 图表白屏换台机器打开HTML什么都没有现象本地生成的 HTML 能正常显示把文件拷到另一台电脑或部署到服务器后图表区域一片空白浏览器控制台里一堆 404。原因PyECharts 默认从 CDN 加载 echarts.min.js 和扩展 JS。本地能显示是因为机器能访问外网内网环境或服务器没有外网权限时JS 加载失败图表就成了空壳。解决开启离线模式把 pyecharts 需要的静态资源下载到本地生成 HTML 时引用本地 JS 文件。如果在 Flask 里部署就把本地静态文件挂到/static目录模板引用改成相对路径。最省事的验证方法打开生成的 HTML看script src...指向的是不是http开头的 CDN 链接是就说明它依赖外网。这个坑最隐蔽因为它不报错是“看起来一切正常但什么都没有”的玄学问题。5.3 内存溢出几十万行数据把进程卡死现象订单表有几十万行read_csv之后一旦做 groupby 或 merge内存占用飙升程序卡顿甚至被杀进程。原因pandas 默认把整数列读成 int64、浮点读成 float64几十万行本身不大但三张表 join 成宽表后列数膨胀再加上后续操作产生中间副本内存就爆了。解决一是读取时用dtype参数指定精确类型比如{user_id: int32, amount: float32}几行代码省一半内存二是聚合前只保留需要的列别扛着整张宽表到处跑三是数据真的过千万行就按月份分块读算完一块释放一块。这类项目里的多数“卡死”都不是数据量真的大而是类型没优化、中间副本太多。5.4 冷启动新用户没有历史订单推荐列表为空现象拿一个新注册的用户 ID 去调 recommend()返回空列表或者因为评分矩阵里没有这个用户直接报 KeyError。原因协同过滤本质上是在找历史相似用户新用户没有订单记录用户向量全 0和所有人的相似度都是 0自然推荐不出东西。这是协同过滤的先天天花板不是代码 bug。解决项目里常见的回退策略是热度兜底——目标用户在评分矩阵中查不到或者推荐结果为空时fallback 到按 heat_score 排名的热门景点 Top10。实现上就是在 recommend() 入口加一个判断if user_id not in rating_matrix.index: return heat_top10。回退逻辑虽然简单但要在注释里写清楚否则业务方会以为推荐系统坏了。5.5 环境不一致本地能跑通服务器上启动就报错现象本地python main.py一切正常按部署说明操作服务器上却报缺少依赖、语法错误或者端口占用。原因本地和服务器 Python 版本不一致比如本地 3.8 写的字典合并语法在 3.7 上直接语法错误或者 requirements.txt 没锁版本服务器装了新版 pyecharts 导致 API 变了。这是最典型的“本地好好的生产就翻车”场景。解决部署前强制三件事服务器上用python -m venv venv建独立环境别污染系统 Pythonpip install -r requirements.txt前确认 pip 能访问到指定版本启动命令用相对路径别写死绝对路径。如果部署说明里写了 Python 版本就按那个版本装别自作聪明升级。环境问题占了这类项目排错时间的大头越是看似简单的问题越容易阴沟里翻船。6. 部署与验证让源码真正成为能交付的东西6.1 部署说明里的命令怎么读部署说明一般会写这样的命令序列python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install -r requirements.txt python main.py每行都要看懂python -m venv venv创建隔离环境避免污染系统 Pythonsource是激活Windows 命令不同pip install -r按锁定的版本安装依赖最后python main.py启动。如果 main.py 里用的是 Flask 调试模式部署时记得关掉debugTrue否则页面报错会把完整堆栈甩给访问者安全性和观感都差。6.2 自测清单数据、图表、推荐三关怎么验收部署完别急着交付按这张表过一遍关卡检查项预期结果数据关打印订单量和缺失值数量级和部署说明一致无新增缺失图表关打开 top10_bar.html中文正常、柱状图按热度排序推荐关抽 3 个老用户调 recommend列表非空且包含其偏好类别的景点三关全过这套源码才算真正跑通。跑通之后再做两件事一是把样例数据换成自己的数据注意列名必须和源码一致不然 merge 会直接报错二是把 heat_score 的加权系数调一版对比两版结果这是数据分析项目最有价值的扩展练习。我自己的习惯是拿到任何“源码部署说明”的包第一件事永远是先读 requirements、再读 main.py、最后才跑代码顺序反了就容易在环境问题上消磨掉耐心。这个项目从解压到换自己的数据跑通熟练的话半天足够是投入产出比很高的一个实战方向。希望帮到你。本文还有配套的精品资源点击获取