首页 / 资讯中心 / 文章详情

机票数据分析可视化避坑指南:从清洗到业务图表实战

机票数据分析可视化避坑指南:从清洗到业务图表实战 ★ FEATURED ARTICLE
简介这是一份面向计算机专业本科生的Python数据分析与可视化实战项目专为课程设计、期末大作业及项目能力提升打造聚焦机票价格数据的清洗、建模、预测与交互式展示。资源包含37个文件主体为11个Python脚本含PyQt5界面开发、回归分析、数据预处理与多维度可视化模块、9个CSV原始及处理后数据集、6个PNG图表结果图、2个UI设计文件及配套README说明文档整体压缩包仅1.33MB轻量易部署。已有402人学习下载项目源自大三学生高分结课作业经导师指导获评99分代码结构清晰、注释完整、环境依赖明确小白可直接运行并理解全流程从数据加载、缺失值处理、特征工程到线性回归预测再到基于PyQt5构建的可交互可视化界面涵盖航空公司、出发地、停靠次数等多维价格影响因素分析图表。1. 为什么机票数据一上图就“假热闹”真实业务场景里90%的可视化大作业栽在清洗和维度错位上你交过一份“高分机票数据分析可视化大作业”图表漂亮、配色高级、动态交互拉满——老师给分很高但你自己心里清楚那张热力图根本没反映真实出票规律那个时间趋势线是用resample(D).mean()硬平滑出来的连节假日调休都没打标柱状图里“北京→上海”和“上海→北京”被当成两个独立航线却没做方向归一化最要命的是票价字段里混着“¥1280”“1280元”“1280.00”“NULL”“暂无报价”……你用pd.to_numeric(..., errorscoerce)一把清掉结果把所有促销价里的“-50”满减券也变成了NaN。这不是代码问题是业务语义没吃透就开画。这篇笔记不讲怎么用Plotly做出炫酷3D航线图而是带你用Python把一张真实的机票数据表——从原始CSV开始抠出时间、航线、价格、舱等、折扣逻辑这五个业务锚点再用MatplotlibSeaborn稳扎稳打地画出能经得起追问的图比如“为什么6月15日早8点北京飞三亚的经济舱均价突然跳涨37%是不是航司临时调舱”——这种图才是企业真正在用的分析起点。适合刚学完Pandas基础、正卡在“数据能跑通但图不敢信”阶段的同学也适合带学生做课程设计的讲师——你拿去就能当课堂实操脚本用。2. 用Pandas把机票CSV“扒皮拆骨”五步定位业务字段拒绝盲目df.head()机票数据源千差万别有OTA平台爬取的含促销标签、库存状态、有航司内部导出的含舱位代码、运价基础、还有第三方聚合API返回的字段名全英文缩写。但无论哪一种必须先锁定五个不可妥协的业务字段出发时间、到达时间、出发地、目的地、票价。其他字段如“是否直飞”“承运航司”“退改规则”都是锦上添花而这五个是画图的“地基”。下面以某次实际教学用的模拟数据集flight_data_2024.csv12.7MB共83,421条记录为例演示如何用Pandas精准定位并清洗。2.1 用dtypes和nunique()揪出“伪数值字段”直接df.info()会告诉你price列是object类型——这说明它混了字符串。但更危险的是那些看似数值、实则藏雷的字段# 查看price列的值分布关键 print(df[price].value_counts(dropnaFalse).head(10)) # 输出示例 # ¥1,280.00 1243 # 1280 892 # 暂无报价 301 # NULL 47 # NaN 12提示value_counts(dropnaFalse)比df[price].unique()更实用——它暴露高频异常值。看到“暂无报价”和“NULL”并存说明数据源有多个清洗环节必须统一处理。真正要做的不是立刻to_numeric而是先建映射字典# 定义清洗规则字符串→数值异常值→np.nan price_map { 暂无报价: np.nan, NULL: np.nan, —: np.nan, : np.nan } # 先替换字符串异常值 df[price_clean] df[price].replace(price_map) # 再用正则提取数字兼容¥1,280.00和1280 df[price_clean] df[price_clean].str.replace(r[^\d.-], , regexTrue) df[price_clean] pd.to_numeric(df[price_clean], errorscoerce)参数说明str.replace(r[^\d.-], , regexTrue)中的正则[^\d.-]表示“非数字、非点、非负号”的所有字符比简单strip(¥元)更鲁棒——能同时处理¥1,280.00、1280元、-50满减券errorscoerce确保无法转为数字的值变NaN而不是报错中断流程新增price_clean列而非覆盖原列保留原始字段供溯源。2.2 时间字段必须拆解为“业务时间粒度”机票的时间字段常以departure_time: 2024-06-15 07:45:00形式存在但单纯转datetime远远不够。你需要根据分析目标拆解分析需求必须提取的字段Pandas代码看早/中/晚航班占比departure_hour0-23整数df[dep_hour] pd.to_datetime(df[departure_time]).dt.hour看工作日vs周末出行departure_weekday0周一df[dep_weekday] pd.to_datetime(df[departure_time]).dt.weekday看提前购票天数days_before_departuredf[dep_date] pd.to_datetime(df[departure_time]).dt.datedf[book_date] pd.to_datetime(df[booking_time]).dt.datedf[days_before_dep] (df[dep_date] - df[book_date]).dt.days血泪经验dt.weekday返回0-6周一到周日但业务上常需“是否周末”布尔值。别写df[dep_weekday].isin([5,6])直接df[is_weekend] df[dep_weekday].isin([5,6])——变量名即文档后续画图时hueis_weekend一目了然。2.3 航线字段要做“方向归一化”否则统计失真原始数据中“北京→上海”和“上海→北京”是两条不同航线但业务上它们属于同一对城市对City Pair。若不做归一化热力图会显示“北京→上海”热度高、“上海→北京”热度低而实际是同一市场# 创建标准化航线ID按字母序排列起降城市 df[city_pair] df[[origin, destination]].apply( lambda x: -.join(sorted([x[origin], x[destination]])), axis1 ) # 示例originSHA, destinationPEK → city_pairPEK-SHA为什么必须用sorted()因为min(x[origin], x[destination]) - max(...)在中文城市名下会失效“北京”“上海”但Unicode码点“北”“上”sorted()按字典序安全。3. Seaborn画图不是调色板大赛用5类图解决机票分析的5个核心问题可视化不是把数据塞进sns.barplot()就完事。每张图必须回答一个具体业务问题且图的结构要匹配问题逻辑。以下5张图是我带学生做期末大作业时被企业导师反复要求重画的高频图——因为它们直击机票业务本质。3.1 问题“哪些城市对最热门” → 用水平条形图排序拒绝默认索引错误做法sns.countplot(ycity_pair)——y轴顺序是数据原始顺序热门航线可能被挤在中间看不见。正确做法先按频次排序再画图# 统计各城市对出现次数并取Top 10 top_pairs df[city_pair].value_counts().head(10) # 用seaborn画水平条形图注意order参数 plt.figure(figsize(10, 6)) sns.barplot(ytop_pairs.index, xtop_pairs.values, paletteBlues_r) plt.title(Top 10 城市对航班数量2024上半年, fontsize14) plt.xlabel(航班数量) plt.ylabel(城市对) plt.tight_layout() plt.show()关键参数ytop_pairs.indexy轴是排序后的城市对名称xtop_pairs.valuesx轴是对应频次paletteBlues_r_r表示反向色阶深蓝→浅蓝符合“数量越多颜色越深”的直觉tight_layout()避免y轴标签被截断——这是学生作业里最高频的“丑图”原因。3.2 问题“票价随出发时间怎么变” → 用箱线图揭示波动拒绝均值陷阱错误做法sns.lineplot(xdep_hour, yprice_clean, datadf)——一条平滑线掩盖了早8点票价既有¥320也有¥2800的真相。正确做法用箱线图展示每小时票价的分布# 过滤掉票价异常值避免箱线图被极端值撑开 q1, q3 df[price_clean].quantile([0.25, 0.75]) iqr q3 - q1 lower_bound q1 - 1.5 * iqr upper_bound q3 1.5 * iqr df_filtered df[(df[price_clean] lower_bound) (df[price_clean] upper_bound)] plt.figure(figsize(12, 6)) sns.boxplot(datadf_filtered, xdep_hour, yprice_clean, orderrange(0, 24), # 强制x轴0-23小时完整显示 fliersize1) # 减小离群点大小避免遮挡箱体 plt.title(各出发小时票价分布剔除异常值, fontsize14) plt.xlabel(出发小时) plt.ylabel(票价元) plt.xticks(range(0, 24, 2)) # 每2小时标一个刻度避免拥挤 plt.grid(True, alpha0.3) plt.show()为什么箱线图比折线图合适箱体高度四分位距IQR直观显示价格离散程度中位线位置典型票价比均值抗异常值干扰离群点fliers单独标出方便定位“早班机高价票”或“深夜特价票”这类业务线索。3.3 问题“经济舱和商务舱价格差多少” → 用分组小提琴图暴露分布差异错误做法sns.barplot(xcabin_class, yprice_clean, datadf)——只显示均值掩盖商务舱价格跨度远大于经济舱的事实。正确做法小提琴图箱线图叠加plt.figure(figsize(10, 6)) sns.violinplot(datadf_filtered, xcabin_class, yprice_clean, innerbox, # 在小提琴内部画箱线图 palette{Economy: #2E8B57, Business: #DC143C}) plt.title(经济舱 vs 商务舱票价分布对比, fontsize14) plt.xlabel(舱位等级) plt.ylabel(票价元) plt.show()参数深意innerbox小提琴图显示密度分布箱线图显示中位数、四分位数二者互补手动指定palette绿色代表经济舱常用色红色代表商务舱高价值感符合业务认知若数据中舱位字段名为cabin且含Y/C/F代码务必先映射df[cabin_class] df[cabin].map({Y: Economy, C: Business, F: First})。4. 避坑机票可视化里最常踩的5个“玄学”坑每个都让老师当场扣分这些坑不是代码语法错误而是业务理解偏差导致的图表失真。我带过的32份作业里90%的“高分但经不起问”都栽在这几处。4.1 坑用groupby().mean()算“平均票价”却忘了折扣券是负数现象计算出的“北京→上海平均票价”是¥1120但实际查销售系统发现主流价格是¥980差价来自未处理的满减券。原因原始price字段含-50满减50元、¥1280-券等to_numeric后变成-50.0拉低了均值。解决清洗时区分“基础票价”和“优惠抵扣”。若无原始字段用规则过滤df df[df[price_clean] 0]——票价不可能为负或零。4.2 坑热力图用pivot_table(indexorigin, columnsdestination, valuescount)但没做方向归一化现象热力图显示“PEK→SHA”热度高、“SHA→PEK”热度低被质疑“上海人不爱回北京”原因origin/destination直接作行列未归一化为city_pair导致同一城市对被拆成两格。解决先创建city_pair列再pivot_table(indexcity_pair, columnsdep_hour, valuescount)——确保每个城市对只占一行。4.3 坑时间序列图用resample(D).mean()却忽略节假日调休影响现象2024年清明节4月4日前后票价曲线平滑看不出假期效应。原因resample(D)按自然日聚合但4月3日调休上班和4月4日法定假日业务逻辑相反。解决添加is_holiday列用国家法定假日表可从holidays库获取标记画图时用hueis_holiday分组。4.4 坑用plt.pie()画舱位占比但没合并小比例舱位现象饼图里出现12个扇区其中“头等舱”仅0.3%标签挤成一团。原因未对低频类别做“其他”合并。解决cabin_counts df[cabin_class].value_counts(normalizeTrue) * 100 others cabin_counts[cabin_counts 2].sum() # 合并2%的舱位 cabin_counts cabin_counts[cabin_counts 2] cabin_counts[其他] others4.5 坑地图航线图用经纬度画直线却不知地球是球面现象北京→洛杉矶航线在平面地图上画成斜线与实际航路大圆航线偏差巨大。原因geopandas或folium默认用墨卡托投影直线连接未调用geopy.distance.great_circle计算球面距离。解决若需精确航线用geopy计算大圆路径点或直接使用plotly.express.scatter_geo()——它内置球面投影。5. 进阶技巧用Matplotlib子图布局Seaborn嵌套做出“一页纸说清业务”的高分报告企业看数据报告第一眼不是看图美不美而是3秒内能否抓住核心结论。我教学生做期末大作业时强制要求最后一张图必须是“四宫格子图”左上趋势、右上分布、左下对比、右下相关性。这张图不追求炫技但必须让老师一眼看出你懂业务。5.1 四宫格布局代码模板可直接抄# 创建2x2子图共享y轴范围让价格对比更直观 fig, axes plt.subplots(2, 2, figsize(14, 10), shareyTrue) fig.suptitle(机票业务核心洞察2024上半年, fontsize16, fontweightbold) # 左上每日航班量趋势突出节假日 daily_flights df.groupby(df[dep_date].dt.date).size() axes[0, 0].plot(daily_flights.index, daily_flights.values, linewidth2, color#1f77b4) axes[0, 0].set_title(每日航班量趋势, fontsize12) axes[0, 0].set_ylabel(航班数量) axes[0, 0].grid(True, alpha0.3) # 右上票价分布直方图叠加核密度估计 sns.histplot(datadf_filtered, xprice_clean, kdeTrue, axaxes[0, 1], color#2ca02c, bins30) axes[0, 1].set_title(票价分布核密度估计, fontsize12) axes[0, 1].set_xlabel(票价元) # 左下工作日vs周末票价箱线图 sns.boxplot(datadf_filtered, xis_weekend, yprice_clean, axaxes[1, 0], palette[#1f77b4, #ff7f0e]) axes[1, 0].set_title(工作日 vs 周末票价对比, fontsize12) axes[1, 0].set_xlabel(是否周末) axes[1, 0].set_ylabel(票价元) # 右下提前购票天数vs票价散点图加趋势线 sns.scatterplot(datadf_filtered, xdays_before_dep, yprice_clean, alpha0.4, s10, axaxes[1, 1], color#d62728) sns.regplot(datadf_filtered, xdays_before_dep, yprice_clean, scatterFalse, axaxes[1, 1], colorblack, line_kws{linestyle:--}) axes[1, 1].set_title(提前购票天数 vs 票价含趋势线, fontsize12) axes[1, 1].set_xlabel(提前购票天数) axes[1, 1].set_ylabel(票价元) plt.tight_layout() plt.show()为什么这个布局能拿高分左上趋势图用linewidth2和color#1f77b4Matplotlib默认蓝保证清晰度不加多余装饰右上直方图KDEkdeTrue让分布形态更易读bins30避免过度分箱左下箱线图用不同颜色区分工作日/周末shareyTrue让y轴刻度一致便于横向比较右下散点图趋势线alpha0.4降低点密度干扰regplot的虚线趋势直观显示“提前购票越久票价越低”的业务规律。5.2 关键细节字体、网格、标题的“隐形加分项”学生常忽略这些但老师批改时会下意识打分元素推荐设置为什么重要字体plt.rcParams[font.sans-serif] [SimHei, Arial Unicode MS]解决中文乱码SimHei是Windows默认黑体兼容性最好网格ax.grid(True, alpha0.3, linestyle--)网格线太粗像表格太淡看不见alpha0.3是经验值标题字号fontsize14主图、fontsize12子图大于14显浮夸小于12难阅读12/14是学术报告黄金比图例位置plt.legend(locupper right, frameonTrue, fancyboxTrue, shadowTrue)frameonTrue加边框fancyboxTrue圆角shadowTrue阴影——细节体现专业度最后说句实在话我带过的学生里最终拿A的不是代码最炫的那个而是在答辩时能指着图说清楚“这个峰为什么在6月15日”“这条线为什么在周四拐弯”的人。可视化不是终点是把数据翻译成业务语言的桥梁。你画的每一张图都应该准备好被问一句“这个结论能指导运营做什么”——希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站