机票数据分析与可视化大作业:从数据清洗到ECharts交互看板

发布时间:2026/10/2 3:03:07

机票数据分析与可视化大作业:从数据清洗到ECharts交互看板 简介这是一份面向计算机相关专业学生与项目实战学习者的Python数据分析可视化大作业完整源码聚焦机票价格数据分析与预测并借助PyQt5实现可视化界面展示适合正在准备课程设计、期末大作业或需要练手数据分析项目的人群。资源包共37个文件压缩后约1.33MB包含11个py源码文件、9个csv数据集、6个xml配置、6张png图表、2个ui界面文件及说明文档覆盖数据预处理、回归分析、回归可视化、数据可视化等核心模块目录结构清晰便于按功能模块查阅与二次开发。目前已有402人学习下载。项目经导师指导并认可评审分99分代码完整可运行读者可据此掌握从原始数据清洗到价格预测建模、再到PyQt5界面交互展示的完整流程同时获得可复用的分析脚本与图表产出适合作为课程设计参考或项目实战练习素材。1. 机票数据分析与可视化一份大作业怎么做出生产级质感机票价格是典型的时序数据却又比股票、气温难缠得多——同一条航线一天内可能被爬虫抓到十几个价位航司放票策略、舱位等级、中转方案、退改签规则全搅在一起。很多同学拿到「机票数据分析与可视化」这个大作业标题第一反应是找份 CSVdf.describe()跑一遍再plt.plot()画条折线就交差。结果答辩时老师一句「你这个价格波动为什么在周二凌晨出现低谷」就能问穿。这份作业真正的价值不在图表数量而在于你能不能把原始脏数据变成一条能自圆其说的分析链路清洗掉重复抓取、对齐时间粒度、拆出航线维度、再让可视化替结论说话。适合正在做 Python 数据分析课程设计、需要一份能拿高分且经得起追问的从业者和学生也适合想用真实业务数据练手 pandas 与 ECharts 的入门者。下面按我实际做过的顺序把选型、清洗、分析、可视化到避坑完整走一遍。2. 数据从哪来、字段怎么定先想清楚分析目标再动手2.1 机票数据的三个来源与取舍做机票分析数据来源直接决定后面能分析什么。常见做法有三类我一般会先评估再选来源典型字段优点坑公开数据集Kaggle/天池类航司、起降机场、价格、日期干净、可直接用字段少缺舱位和中转自己写爬虫抓取航班号、价格、抓取时间、舱位字段可控、时效新反爬、IP 封禁、数据重复航司开放接口/模拟数据结构化、含余票稳定需申请作业场景常拿不到大作业场景我建议优先用公开数据集打底再补一小段自己抓的实时数据做对比这样既有规模又有「新鲜感」。如果标题里强调「可视化大屏」那数据量至少要撑得起多图表联动几千条起步比较稳。2.2 字段设计别等分析时才发现缺列很多人抓完数据才发现没有「抓取时间」这一列导致无法分析价格随时间的变化。我一般会强制保留这几列flight_no航班号用于区分同一航线不同班次airline航司做航司维度对比dep_city/arr_city出发到达城市航线分析的基础dep_time/arr_time起降时间用于时段分析price价格核心指标cabin舱位等级经济舱/商务舱价格差异巨大crawl_time抓取时间戳时序分析的关键is_direct是否直飞中转会显著影响价格字段定好后用 pandas 读进来先看一眼结构和缺失情况import pandas as pd # 读取原始数据注意编码机票数据常含中文城市名 df pd.read_csv(flights_raw.csv, encodingutf-8) # 基础体检形状、类型、缺失、重复 print(df.shape) print(df.dtypes) print(df.isnull().sum()) print(df.duplicated(subset[flight_no, crawl_time]).sum())这段代码的作用是先摸清数据底细。shape看规模dtypes确认price是不是被读成了字符串常见翻车点isnull().sum()定位缺失列duplicated按「航班号抓取时间」判断重复抓取。参数上subset一定要选能唯一标识一条记录的字段组合否则会把正常的多条记录误判为重复。2.3 时间字段解析机票分析最容易翻车的地方机票数据里的时间格式五花八门2024/3/5 08:30、2024-03-05 8:30、甚至05-Mar-24都可能出现。统一解析是后续所有时序分析的前提# 统一时间格式errorscoerce 把解析失败的置为 NaT 而不是报错 df[dep_time] pd.to_datetime(df[dep_time], errorscoerce) df[crawl_time] pd.to_datetime(df[crawl_time], errorscoerce) # 解析失败的行要单独看不能直接丢 bad_rows df[df[dep_time].isnull()] print(f解析失败 {len(bad_rows)} 行) print(bad_rows[[flight_no, dep_time]].head()) # 派生字段出发小时、星期、是否周末 df[dep_hour] df[dep_time].dt.hour df[dep_weekday] df[dep_time].dt.weekday df[is_weekend] df[dep_weekday].isin([5, 6])errorscoerce是关键参数它让解析失败变成NaT而不是抛异常中断整个流程。派生出的dep_hour、dep_weekday是后面分析「什么时段机票便宜」「周末是否更贵」的基础。这一步做完数据才算真正可用。3. 清洗与特征工程把脏数据变成能分析的宽表3.1 去重、异常价与缺失值处理原始机票数据里重复抓取和异常价格是两大污染源。同一航班同一抓取时间被记录两次会让统计结果虚高价格出现 0 或 99999 这种极端值会毁掉均值。处理逻辑# 1. 按航班号抓取时间去重保留第一条 df df.drop_duplicates(subset[flight_no, crawl_time], keepfirst) # 2. 价格异常值处理用分位数截断避免个别极端值带偏 q_low df[price].quantile(0.01) q_high df[price].quantile(0.99) df df[(df[price] q_low) (df[price] q_high)] # 3. 关键字段缺失直接删非关键字段填充 df df.dropna(subset[price, dep_city, arr_city]) df[cabin] df[cabin].fillna(经济舱)分位数截断比直接设阈值更稳因为不同航线价格量级差异大固定阈值会误伤。quantile(0.01)和quantile(0.99)把最极端的 2% 去掉保留主体分布。这一步的参数要根据数据实际分布调如果数据本身很干净可以放宽到 0.005/0.995。3.2 航线维度与价格区间特征机票分析的核心维度是「航线」也就是出发城市到到达城市的组合。把两个字段拼成一个新字段后续 groupby 会方便很多# 构造航线字段 df[route] df[dep_city] - df[arr_city] # 价格分箱用于分布分析 bins [0, 500, 1000, 1500, 2000, 3000, 10000] labels [500以下, 500-1000, 1000-1500, 1500-2000, 2000-3000, 3000以上] df[price_level] pd.cut(df[price], binsbins, labelslabels) # 看热门航线 Top10 top_routes df[route].value_counts().head(10) print(top_routes)pd.cut做等距分箱labels让结果可读。分箱边界要结合数据实际价格范围定如果数据集中在 800-1200那 bins 就要相应加密。value_counts()快速看出哪些航线数据量大数据量太少的航线在后续分析里要谨慎下结论。3.3 按航线和时间聚合生成分析用的宽表清洗完的明细数据还不能直接画图需要聚合成「航线-日期-均价」这样的宽表# 按航线和出发日期聚合算均价、最低价、航班数 route_daily df.groupby([route, df[dep_time].dt.date]).agg( avg_price(price, mean), min_price(price, min), max_price(price, max), flight_count(flight_no, count) ).reset_index() route_daily.columns [route, dep_date, avg_price, min_price, max_price, flight_count] print(route_daily.head()) # 按航司聚合做航司对比 airline_stat df.groupby(airline).agg( avg_price(price, mean), total_flights(flight_no, count) ).sort_values(avg_price, ascendingFalse)groupby后接agg可以一次算出多个统计量比循环高效得多。reset_index()把分组键还原成列方便后续导出和画图。这一步产出的route_daily就是可视化阶段的主力数据源airline_stat用于航司对比图。4. 可视化落地从静态图到可交互看板4.1 用 Matplotlib 快速出探索性图表分析阶段先用 Matplotlib 快速看趋势不用追求美观重点是验证结论import matplotlib.pyplot as plt import matplotlib # 中文显示配置不做这步中文全是方块 matplotlib.rcParams[font.sans-serif] [SimHei] matplotlib.rcParams[axes.unicode_minus] False # 选一条热门航线看价格趋势 sample route_daily[route_daily[route] 北京-上海].sort_values(dep_date) plt.figure(figsize(12, 5)) plt.plot(sample[dep_date], sample[avg_price], markero, label均价) plt.plot(sample[dep_date], sample[min_price], markers, label最低价, linestyle--) plt.xlabel(出发日期) plt.ylabel(价格元) plt.title(北京-上海航线价格趋势) plt.legend() plt.xticks(rotation45) plt.tight_layout() plt.savefig(route_trend.png, dpi150)font.sans-serif设成SimHei是中文环境的标准操作Linux 上可能要用WenQuanYi之类字体。tight_layout()防止标签被裁掉dpi150保证导出清晰度。这张图用来快速判断价格是否有周期性波动是后续深入分析的方向指引。4.2 用 ECharts 做可交互可视化大屏大作业如果要求「可视化大屏」ECharts 是性价比最高的选择。核心思路是后端把聚合数据转成 JSON前端用 ECharts 渲染。先准备数据接口import json # 把航线均价数据转成 ECharts 需要的格式 route_avg df.groupby(route)[price].mean().sort_values(ascendingFalse).head(15) chart_data { routes: route_avg.index.tolist(), prices: [round(p, 2) for p in route_avg.values.tolist()] } with open(route_avg.json, w, encodingutf-8) as f: json.dump(chart_data, f, ensure_asciiFalse)ensure_asciiFalse保证中文正常写入否则会变成\uXXXX转义。round(p, 2)控制小数位避免前端显示一长串。这个 JSON 就是前端 ECharts 的数据源。前端渲染部分// 读取后端生成的 JSON渲染柱状图 fetch(route_avg.json) .then(res res.json()) .then(data { const chart echarts.init(document.getElementById(routeChart)); chart.setOption({ title: { text: 热门航线均价 Top15 }, tooltip: { trigger: axis }, xAxis: { type: category, data: data.routes, axisLabel: { rotate: 45 } }, yAxis: { type: value, name: 均价元 }, series: [{ type: bar, data: data.prices, itemStyle: { color: #5470c6 } }] }); });echarts.init绑定容器setOption里xAxis的rotate: 45防止航线名重叠。tooltip的trigger: axis让鼠标悬停显示整列数据。这套结构可以复制到折线图、饼图只改series.type即可。4.3 时段热力图把「什么时候买便宜」讲清楚机票分析最有说服力的图表之一是「出发时段 vs 价格」的热力图。用 pandas 透视表生成矩阵再交给 ECharts 的 heatmap# 按出发小时和星期做透视值取均价 pivot df.pivot_table( valuesprice, indexdep_weekday, columnsdep_hour, aggfuncmean ).round(0) # 转成 ECharts heatmap 需要的 [x, y, value] 格式 heat_data [] for y, row in enumerate(pivot.values): for x, val in enumerate(row): if not pd.isna(val): heat_data.append([x, y, int(val)]) print(f热力图数据点{len(heat_data)})pivot_table的aggfuncmean算均价round(0)取整。转成[x, y, value]三元组是 ECharts heatmap 的标准输入格式。pd.isna过滤掉没有数据的格子否则前端会显示异常。这张图能直观回答「周二凌晨是不是真的便宜」这类答辩高频问题。5. 避坑与排查机票分析里那些血泪经验5.1 价格字段被读成字符串统计全错现象df[price].mean()报错或者返回奇怪结果describe()里 price 显示为 object 类型。原因原始 CSV 里价格带了货币符号如¥1200或千分位逗号1,200pandas 默认按字符串读入。解决读入时用dtype{price: float}强制转换或者读入后清洗df[price] df[price].astype(str).str.replace(r[¥,], , regexTrue).astype(float)str.replace用正则一次去掉货币符号和逗号再转 float。这一步不做后面所有价格统计都是错的。5.2 时区不统一导致时序分析错位现象价格趋势图在凌晨出现莫名其妙的尖峰或者同一天的数据被拆成两天。原因抓取时间用了 UTC而起降时间是本地时间两者混用导致时间对齐错误。解决统一到一个时区通常用出发地本地时间df[crawl_time] pd.to_datetime(df[crawl_time], utcTrue).dt.tz_convert(Asia/Shanghai).dt.tz_localize(None)tz_convert转时区tz_localize(None)去掉时区信息变成 naive 时间方便和起降时间对齐。时区问题不解决所有按天的聚合都不可信。5.3 重复抓取没去干净均价被拉偏现象某条航线均价明显高于预期检查发现同一航班被记录了多次。原因爬虫重试机制导致同一时间点抓了两次或者drop_duplicates的 subset 选错。解决用「航班号抓取时间价格」三个字段联合去重并检查去重前后行数变化before len(df) df df.drop_duplicates(subset[flight_no, crawl_time, price], keeplast) print(f去重前 {before} 行去重后 {len(df)} 行删除 {before - len(df)} 行)keeplast保留最新一条因为后抓的通常更准。打印删除行数是为了确认去重逻辑没有误删正常数据。5.4 中文乱码让图表标题变方块现象Matplotlib 图表里中文全是方框ECharts 里中文正常。原因Matplotlib 默认字体不含中文需要手动指定。解决除了前面设font.sans-serifLinux 服务器上还要确认字体已安装# 查看系统可用中文字体 fc-list :langzh如果没有输出需要安装中文字体包。Windows 上一般有SimHeiMac 上用Arial Unicode MS。这个坑不解决导出的图直接不能用。5.5 数据量太大导致前端卡死现象ECharts 渲染几万个点时页面卡顿甚至崩溃。原因把明细数据直接丢给前端没有做聚合。解决后端先聚合再传前端只渲染聚合后的结果。比如热力图最多 7×24168 个点柱状图 Top15 就 15 个点。明细数据留在后端做分析前端只负责展示结论。6. 让这份作业真正拿高分的两个进阶技巧第一个技巧是给分析加「对照组」。单独说「北京-上海均价 1200」没有说服力但如果说「北京-上海均价 1200比北京-广州高 18%且周末溢价达 25%」结论立刻立体。实现上就是多做几次 groupby 再算比值# 航线均价对比算相对基准的溢价 base df[df[route] 北京-上海][price].mean() compare df.groupby(route)[price].mean().reset_index() compare[premium_pct] ((compare[price] - base) / base * 100).round(1) compare compare.sort_values(premium_pct, ascendingFalse) print(compare.head(10))premium_pct就是相对基准航线的溢价百分比答辩时这种相对指标比绝对值更能体现分析深度。第二个技巧是加一个「预测」小模块。不用上复杂模型用statsmodels做个简单的季节性分解或移动平均就能让作业从「描述性分析」升级到「预测性分析」from statsmodels.tsa.seasonal import seasonal_decompose # 取一条航线的时间序列 ts route_daily[route_daily[route] 北京-上海].set_index(dep_date)[avg_price] ts ts.asfreq(D).interpolate() # 补齐缺失日期 # 季节性分解period7 表示按周周期 result seasonal_decompose(ts, modeladditive, period7) result.plot()asfreq(D)把时间序列对齐到每天interpolate()补缺失值period7假设一周一个周期。分解出的趋势项和季节项能直接支撑「价格有周期性」的结论。这个模块代码量不大但能让老师看到你懂时序分析的基本套路。我自己做这类作业最大的教训是别一上来就堆图表。先把数据清洗和时间对齐做扎实再想「这张图要回答什么问题」。图表是结论的载体不是装饰。一份能拿高分的机票分析核心是让每个数字都有出处、每个结论都能追溯到某段代码。希望帮到你。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/2 3:03:07

CDC实时监听数据库全解析:从原理到Debezium+Kafka实战

CDC(Change Data Capture,变更数据捕获)是这几年来数据库圈子里绕不开的话题。尤其当业务系统需要实时感知数据库里的增删改查,把数据同步到消息队列、数仓、缓存或者另一个数据库时,CDC几乎成了标准答案。我最早接触这…

2026/10/2 3:03:07

POE+DC双供电方案:让温湿度监测项目供电成本直降37%

一个做仓储环境监测的朋友年中拿下了一个30个点位的温湿度监测项目,报价比同行的方案直降了一截,甲方一度怀疑他是不是要偷工减料。后来甲方工程师打开报价单逐项核对,才发现猫腻在供电方案那一栏里——所有点位从"每处拉一路220V电源配…

2026/10/2 4:23:10

Python异常处理实战:try-except、Traceback与自定义异常

你有没有过这种经历:自己写的Python脚本在本地跑得欢天喜地,一上生产环境,或者换了一批真实数据,瞬间崩成一堆红色Traceback?我前几年做爬虫和数据清洗的时候就经常撞上这种尴尬——明明逻辑想得挺周密,偏偏…

2026/10/2 4:23:10

电子数据取证赛项备赛指南:样题任务书拆解与核心技能训练

2026年安徽省职业院校技能大赛(中职组)电子数据取证技术与应用赛项样题任务书,说实话,在备赛圈里算得上一份“开源地图”。不少队伍手里攒了一堆模拟题,但真正把样题任务书逐条拆透、当成项目来做的人并不多。我带竞赛…

2026/10/2 4:23:10

PHEV能源管理:ADMM与CVX联合求解MPC实时优化

插电式混合动力车辆的能源管理这几年是个热点方向,但大多数资料要么停在"DP全局优化"的理论层面,要么直接丢给你一段黑盒代码。我自己在做MPC控制器落地时最头疼的问题其实是:问题建出来了,CVX也能解,但放到…

2026/10/2 4:23:10

移动通信课后答案高效使用指南:从考点框架到链路预算复盘

简介:《移动通信课后答案.pdf》是一份移动通信课程的课后习题解析资料,主要面向通信工程、电子信息等专业的高校学生,以及正在备考考研或自学移动通信的读者。它围绕教材中的思考题与典型计算题提供详细解答,能帮助读者检验学习效…

2026/10/2 4:23:10

open-code-review:结构化代码合规审查引擎实战指南

1. 这不是另一个“AI写代码”工具——open-code-review 的真实定位与适用边界 阿里 open-code-review 这个名字刚出来时,我第一反应是:又一个带“AI”前缀的代码辅助工具?点开 GitHub 仓库、扫完 README、跑通第一个 demo 后,我立…

2026/10/2 4:18:10

云盘网盘系统源码拆解:存储适配层、部署实战与避坑指南

简介:一套基于PHP开发的云盘网盘系统源码,面向需要搭建私有云存储服务的中小型企业、个人站长及开发者。系统重点支持快速对接阿里云OSS、腾讯云COS、百度云BOS等多家主流云存储服务,通过API调用与身份验证实现灵活切换存储提供商&#xff0c…

2026/10/1 5:21:14

东莞市品牌网站建设报价常见报错与解决

东莞品牌网站建设报价单背后:一份保姆级建站教程避坑实录 网站做好了没人访问,这大概是很多老板最头疼的事。花了大几万做的品牌站,上线后流量惨淡,比路边摊还冷清。别急着骂外包公司,很多“东莞品牌网站建设报价”里藏着不少猫腻,比如用模板站冒充定制…

2026/10/1 17:09:46

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/10/1 10:48:55

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/10/2 0:02:57

PWN入门:从栈溢出原理到ROP链实战

1. 这不是“学PWN”,是重新理解你每天敲的每一行C代码我第一次在CTF赛场上写出能控制程序流的exp时,手抖得连gdb的c命令都输错三次。那道题只有23行C代码,一个gets()调用,一个printf(),一个return——它甚至没开NX&…

2026/10/2 0:02:57

Windows下cudaMallocHost显存占用之谜:WDDM与TCC模式差异及优化方案

1. 一个反直觉的显存占用现象第一次在 Windows 上看到cudaMallocHost把显存吃掉的时候,我的反应是打开任务管理器反复确认了三遍。明明调用的是主机端锁页内存分配,按 CUDA 文档的说法,这块内存应该落在系统 RAM 里,跟 GPU 的显存…

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

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

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