ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Python演唱会数据分析可视化:大作业完整实战指南

Python演唱会数据分析可视化:大作业完整实战指南 简介一套完整的Python演唱会数据分析与可视化大作业源码面向高校学生、课程设计者及数据分析入门者解决从数据获取到业务展示的全流程实践需求。项目以演唱会数据为对象先用爬虫自动化抓取网页信息再用pandas完成缺失值处理、字段转换等清洗工作分析阶段引入Apache Spark进行分布式统计与趋势挖掘最后通过Flask构建后端服务、ECharts渲染交互图表在前端大屏上直观呈现票房、热度等多维指标。资源包共65个文件涵盖Python与Scala源码、HTML/JS前端页面、CSV数据文件、JSON及图片资源等包体约11.86MB目录按爬虫、清洗、分析、展示模块划分便于局部替换或二次开发。目前已有79人学习下载适合希望快速参考完整项目链路、提升大数据可视化能力的学习者。1. 平台演唱会数据分析这个 Python 大作业到底在写什么如果你正在为 Python 大作业发愁打算选数据分析与可视化的方向平台演唱会数据集是一个很聪明的选题它有艺人、城市、场馆、日期、票价、观众数多个维度数据贴近生活可视化做出来也有话题度。这个项目的本质是——从票务平台抓取或整理演唱会原始数据用 pandas 清洗成结构化表再围绕时间、城市、票价做统计分析最后用 matplotlib、seaborn、pyecharts 把结论变成图表甚至可视化大屏交出一份能跑的源码加一份能讲的报告。适合一周内需要完成课程设计或结课大作业的同学也适合刚学完 pandas、想用真实场景练手的人。它不需要机器学习但能把数据处理能力和图表表达练得很扎实这两点正是本科大作业最看重的。2. 先搭数据地基演唱会数据从哪来、怎么整理成 DataFrame2.1 数据来源的三种常见做法爬虫、公开数据集、模拟数据做数据分析项目数据来源直接决定后面要踩多少坑。平台演唱会数据的获取常见做法有三种。第一种是爬虫。用 requests 加 BeautifulSoup 抓取票务平台或音乐平台的演唱会列表页能拿到演唱会名称、艺人、城市、场馆、日期、票价区间等公开字段。这个方案真实感强但要处理反爬、分页、页面结构变化写起来会比较费时间。我一般只建议在大作业中抓少量页面比如几百条就够频率控制在每秒一次以内避免给对方服务器造成压力也避免把自己搞进黑名单。纯技术验证可以用网上的公开页面或官方提供的数据接口不要碰需要登录和验证码的部分。第二种是公开数据集。GitHub、Kaggle 上有不少演唱会或演出历史数据下载成 CSV 或 Excel 后直接读取。这个方案最省事但字段经常不齐有的没有票价有的没有场馆容量需要花时间补全。而且公开数据集的地区、时间分布不一定符合你想讲的故事最后图表和结论可能不太搭。第三种是模拟数据这也是我推荐给赶时间同学的做法。按真实分布用 numpy 构造数据比如票价集中在 180 到 1500 元之间一线城市场次多于二三线城市暑期和年末场次偏多。下面这段代码生成 600 条演唱会记录字段覆盖整个大作业需要的基本维度import pandas as pd import numpy as np rng np.random.default_rng(2024) # 固定随机种子保证结果可复现 cities [北京, 上海, 广州, 深圳, 成都, 杭州, 武汉, 南京, 西安, 长沙] # 每座城市配几个候选场馆模拟数据时保证城市和场馆不会错配 venues { 北京: [国家体育场, 凯迪拉克中心, 北京工人体育场], 上海: [梅赛德斯-奔驰文化中心, 上海体育场], 广州: [广州体育馆, 宝能国际体育演艺中心], 深圳: [深圳湾体育中心, 华润深圳湾体育中心], 成都: [成都金融城演艺中心], 杭州: [杭州奥体中心体育馆], 武汉: [武汉体育中心体育馆], 南京: [南京奥体中心体育馆], 西安: [西安奥体中心体育馆], 长沙: [湖南国际会展中心] } singers [周杰伦, 林俊杰, 陈奕迅, Taylor Swift, 薛之谦, 五月天, 邓紫棋, 张杰] rows [] for i in range(600): city rng.choice(cities) singer rng.choice(singers) year int(rng.integers(2023, 2025)) month int(rng.integers(1, 13)) day int(rng.integers(1, 29)) low int(rng.integers(180, 680)) # 最低票价 high low int(rng.integers(200, 1200)) # 最高票价最低区间长度 rows.append([i, singer, city, rng.choice(venues[city]), f{year}-{month:02d}-{day:02d}, f{low}-{high}, int(rng.integers(8000, 50000))]) df pd.DataFrame(rows, columns[演唱会ID, 艺人, 城市, 场馆, 日期, 票价区间, 观众数]) df.head()代码里的 rng np.random.default_rng(2024) 是固定随机种子每次运行都生成同一份数据交作业时图表、数字、结论都能对上这是大作业的一个隐藏加分项。场馆列表放在字典里城市和场馆天然绑定后面做城市分布时不会出现“上海的国家体育场”这种怪数据。日期先用字符串后面统一转成 pandas 的 datetime 类型。票价区间写成低-高字符串是为了模拟爬虫抓到的原始形态下一步正好演示清洗。如果你确实要写爬虫核心框架大致是这样import requests from bs4 import BeautifulSoup import time def crawl_concert_page(url): # 仅用于学习研究注意遵守目标网站的 robots 协议 resp requests.get(url, headers{User-Agent: Mozilla/5.0}, timeout10) soup BeautifulSoup(resp.text, html.parser) # 先打印页面结构再写具体的选择器 items soup.select(.concert-item) for item in items: title item.select_one(.title).text.strip() city item.select_one(.city).text.strip() date item.select_one(.date).text.strip() price item.select_one(.price).text.strip() # 这里可以追加到列表最后转成 DataFrame return items这段代码是个框架真正的选择器要按你抓的站点的 HTML 结构来写。爬下来的字段通常是字符串比如2024-05-18 周六 19:30和¥380起后面要写正则或 split 提取核心信息。我的建议是爬虫只为演示数据获取能力后续清洗、分析、可视化才是大作业的评分大头别在爬虫上耗太多时间。2.2 用 pandas 清洗日期、票价、城市从字符串里抠出来拿到原始 DataFrame 后的第一件事是清洗。爬虫和模拟数据最大的区别就是脏数据多日期可能带星期几票价可能写380-1280也可能写380起城市名可能带后缀。下面这两个函数是清洗的核心def parse_date(raw): # 兼容 2024-05-18、 2024-05-18 周六、 2024/5/18 等常见格式 s str(raw).split( )[0].replace(/, -) return pd.to_datetime(s, format%Y-%m-%d, errorscoerce) def parse_price(raw): # 输入 380-1280返回最低价、最高价、均价输入 380起 时返回单一价格 s str(raw).replace(¥, ).replace(起, ).replace(元, ) try: parts s.split(-) low float(parts[0]) high float(parts[1]) if len(parts) 1 else low except Exception: return None, None, None return low, high, (low high) / 2 df[日期DT] df[日期].apply(parse_date) df[最低价] df[票价区间].apply(lambda x: parse_price(x)[0]) df[最高价] df[票价区间].apply(lambda x: parse_price(x)[1]) df[票价均值] df[票价区间].apply(lambda x: parse_price(x)[2])parse_date 先把字符串按空格切段取第一段再把斜杠替换成横杠最后用 pd.to_datetime 严格按格式解析。errorscoerce 是关键参数解析不了的值会变成 NaT缺失时间而不是抛异常中断整个脚本这给我们留下了排查的机会。parse_price 先清掉¥、起、元这些干扰词再按横杠切分如果没有横杠说明是单一票价最高价取最低价同一值。这样一次 apply 会调用三次 parse_price数据量小无所谓但更干净的做法是一次调用返回三列df[[最低价, 最高价, 票价均值]] df[票价区间].apply(lambda x: pd.Series(parse_price(x)))清洗完要做一次缺失值检查print(df.isnull().sum()) print(df[df[日期DT].isna()].head())如果日期解析失败很多大概率是格式里有待定、延期这类词这时需要先把这些记录筛掉或标注状态而不是直接丢进分析。票价解析失败则多是价格待定这类值可以先置为 NaN分析时用 dropna 排除。我见过不少大作业翻车在数据清洗这步原始 DataFrame 里一堆字符串直接拿去 groupby结果中文排序乱、日期按字典序排整个报告都不成立。2.3 多表关联的常规做法演唱会表、场馆表合并真实数据很少是一张表往往有演唱会信息表、场馆容量表、艺人信息表。大作业如果只分析单表维度不够丰富合并一张场馆表就能多出上座率这个很有说服力的分析指标。venue_info pd.DataFrame([ [国家体育场, 北京, 91000], [凯迪拉克中心, 北京, 18000], [梅赛德斯-奔驰文化中心, 上海, 18000], [上海体育场, 上海, 56000], [广州体育馆, 广州, 14000], [深圳湾体育中心, 深圳, 20000], [成都金融城演艺中心, 成都, 12000], [杭州奥体中心体育馆, 杭州, 18000], [武汉体育中心体育馆, 武汉, 30000], [南京奥体中心体育馆, 南京, 21000], [西安奥体中心体育馆, 西安, 18000], [湖南国际会展中心, 长沙, 15000] ], columns[场馆, 城市, 容纳人数]) df_merged df.merge(venue_info, on场馆, howleft) df_merged[上座率] df_merged[观众数] / df_merged[容纳人数].clip(lower1) print(df_merged[上座率].describe())merge 用 on场馆 关联两张表里字段同名才写这个参数如果一侧叫场馆另一侧叫场馆名称要写成 on场馆, left_on场馆, right_on场馆名称并且注意合并后列名。howleft 保证左表 600 条演唱会记录全部保留右表没有匹配到的场馆上座率自然是 NaN。clip(lower1) 是防止场馆容量数据为 0 时除零容量 0 会置成 1上座率虽然有值但会很离谱所以后面分析前最好再过滤一次。到这里DataFrame 里已经有了日期、城市、票价、观众数、场馆容量、上座率接下来就可以做真正的分析了。3. 把数据变成洞察演唱会的核心分析维度与统计口径3.1 时间维度用 resample 看场次与票房的月度趋势演唱会数据最直观的分析是时间趋势。把日期列设为索引用 resample 按月聚合就能回答哪个月开唱最多旺季是什么时候这类问题。df df_merged.copy() df[日期DT] pd.to_datetime(df[日期DT]) monthly df.set_index(日期DT).resample(M).agg( 场次数(演唱会ID, count), 观众总数(观众数, sum), 平均票价(票价均值, mean) ).dropna() print(monthly.head())set_index 之后日期成为行索引resample(M) 表示按月Month end分组。agg 里用 named aggregation新列名写在左侧读起来一目了然。dropna 是为了去掉还没有整月数据的最后一个月比如模拟数据只到 2024 年 8 月8 月场次数只有半个月的量画折线时尾部会掉得很明显。如果想看季节规律把月份字段提取出来再做分组df[月份] df[日期DT].dt.month season df.groupby(月份).agg( 场次数(演唱会ID, count), 平均票价(票价均值, mean) ).sort_index() print(season)这里要留心统计口径按场次统计和按观众总数统计峰值可能不一样。比如 5 月场次多但都是小型 livehouse观众总数反而不如 8 月几场大型体育场演唱会。写报告时要把口径写清楚不要只说演唱会旺季在几月而要说按场次统计旺季在 X 月和 Y 月按观众总量统计旺季是 Z 月。这种细节在答辩时非常加分。时间维度另一个常见分析是跨年对比。如果数据覆盖两年先按年份分两组再比较同月份场次可以看到市场整体增长。还有按星期几统计演唱会通常集中在周五和周六用 df[日期DT].dt.dayofweek 就能做出来这个结论贴近大众认知放在报告里很容易引发共鸣。3.2 城市与场馆头部效应、上座率与区域分布演唱会分布从来不是均匀的一线城市占据大量场次这是数据分析报告里最好讲的故事。用 groupby 按城市聚合city_stats df.groupby(城市).agg( 场次数(演唱会ID, count), 观众总数(观众数, sum), 平均票价(票价均值, mean), 平均上座率(上座率, mean) ).sort_values(场次数, ascendingFalse) city_stats[场次占比] (city_stats[场次数] / city_stats[场次数].sum()).round(4) print(city_stats)sort_values(场次数, ascendingFalse) 把热门城市排在前面一眼看到头部效应。场次占比用总和做分母算出北京、上海加起来占多少。如果北京、上海、广州三个城市占了 50% 以上报告里就可以写演唱会市场呈现明显头部聚集效应。上座率的均值这里用的是算术平均严格来说应该按观众总数除以场馆容量总和做加权平均city_stats_adj df.groupby(城市).agg( 观众总数(观众数, sum), 总容量(容纳人数, sum) ) city_stats_adj[加权上座率] city_stats_adj[观众总数] / city_stats_adj[总容量]两种口径算出来的上座率会有差异特别是当一座城市既有十万人的超级体育场也有几千人的小型场馆时算术平均会把小场馆的上座率放大。建议正文用加权口径附录说明两种口径区别这能体现你对数据严谨性的理解。场馆维度可以做最热门场馆 Top10用 value_countstop_venues df[场馆].value_counts().head(10) print(top_venues)结合上座率还能发现一个有意思的现象有些热门场馆场次多但上座率不一定高因为大场馆容量大票房压力也大。这种交叉分析比单列排行榜更有深度。3.3 票价结构区间票价如何拆成档位和分布票价是演唱会的核心经济指标。我们把连续型的票价均值切分成几个档位便于做饼图和柱状图df[票价档位] pd.cut( df[票价均值], bins[0, 300, 600, 1000, 2000], labels[大众, 中档, 高档, VIP] ) price_dist df.groupby(票价档位, observedTrue).agg( 场次数(演唱会ID, count), 平均票价(票价均值, mean), 观众总数(观众数, sum) ) print(price_dist)bins 的边界不是随便写的。我一般先看 describeprint(df[票价均值].describe())如果四分之一分位数是 400中位数是 650那用 300 和 600 做切分是合理的说明大众价位和主流价位能分开。如果最低价都到 500可以用 [0, 600, 1000, 2000] 两档切。pd.cut 的 labels 要和 bins 数量匹配多一个都会报错。observedTrue 用于取消分类变量的警告pandas 2.0 之后不写也没事但写上更稳。票价档位和艺人交叉分析更有意思artist_price df.groupby([艺人, 票价档位], observedTrue).size().unstack(fill_value0) print(artist_price)比如 Taylor Swift 的 VIP 档场次占比远高于本土歌手说明头部国际艺人的票价天花板更高。这个发现可以直接做成堆叠柱状图是报告的核心论点之一。票价数据还能计算价格集中度。用累计占比看比如票价最高的 20% 场次贡献了多少观众。把票价均值排序按累加观众数算占比这一步可以用 cumsum 实现。计算逻辑不复杂但放在报告中非常能体现分析深度。4. 可视化输出从 Matplotlib 基础图到可交互大屏4.1 Matplotlib Seaborn 静态图折线、箱线、热力图分析做完下一步就是把结果画出来。最容易出错的是中文显示先配好全局参数import matplotlib.pyplot as plt import seaborn as sns plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei, PingFang SC] plt.rcParams[axes.unicode_minus] False sns.set_theme(stylewhitegrid, fontSimHei)rcParams 设置 sans-serif 字体列表系统会按顺序找第一个可用的中文字体Windows 上用 SimHeimacOS 上用 PingFang SC这样换电脑也不容易乱码。axes.unicode_minus 必须设成 False不然坐标轴负号显示成方块。月度趋势用折线图fig, ax plt.subplots(figsize(10, 4)) sns.lineplot(datamonthly, xmonthly.index, y场次数, markero, axax) ax.set_title(演唱会月度场次趋势) fig.savefig(output/月度趋势.png, dpi200, bbox_inchestight)linplot 的 x 传 DatetimeIndex 会正确显示时间刻度。dpi200 是印刷质量bbox_inchestight 避免标题被截掉。大作业图片导出用这两参数基本不会翻车。票价分布用箱线图对比城市差异fig, ax plt.subplots(figsize(12, 5)) sns.boxplot(datadf, x城市, y票价均值, ordercity_stats.index[:10], axax) ax.set_xticklabels(ax.get_xticklabels(), rotation45) fig.tight_layout() fig.savefig(output/城市票价箱线图.png, dpi200, bbox_inchestight)order 参数可以指定城市显示顺序不然 seaborn 默认按中文拼音排北京未必在第一个看起来没有逻辑。中文城市名在坐标轴上旋转 45 度避免重叠。tight_layout 自动调整留白。城市与月份交叉的热力图city_month df.pivot_table( index城市, columns月份, values演唱会ID, aggfunccount, fill_value0 ) # 只保留 Top8 城市 city_month city_month.loc[city_stats.index[:8]] fig, ax plt.subplots(figsize(12, 6)) sns.heatmap(city_month, cmapReds, annotTrue, fmtd, axax) ax.set_title(城市×月份 演唱会场次热力图) fig.savefig(output/城市月份热力图.png, dpi200, bbox_inchestight)pivot_table 把行变成城市、列变成月份值是场次数。loc 只取 Top8 城市避免 10 个城市挤在一张图里看不清。annotTrue 显示数字fmtd 表示用整数格式。热力图是可视化大屏之外最有视觉冲击力的静态图建议放在报告第一个分析位置。4.2 用 Pyecharts 生成可交互大屏柱状图、地图、词云静态图适合写报告但如果大作业要求做出可视化大屏或者你想在答辩现场展示动态效果pyecharts 是最顺手的工具。它生成 html 文件浏览器打开就能交互不需要启动本地服务。城市 Top10 柱状图from pyecharts.charts import Bar, Map, WordCloud, Page from pyecharts import options as opts top_cities city_stats.head(10) bar ( Bar(init_optsopts.InitOpts(width900px, height500px)) .add_xaxis(top_cities.index.tolist()) .add_yaxis(场次数, top_cities[场次数].astype(int).tolist()) .set_global_opts( title_optsopts.TitleOpts(title演唱会城市 TOP10), yaxis_optsopts.AxisOpts(name场次) ) ) bar.render(output/city_bar.html)pyecharts 的链式调用很直观add_xaxis 加类目轴add_yaxis 加系列。数值要转成 int 列表避免 numpy int64 类型在 json 序列化时出问题。render 直接生成 html双击就能打开。中国地图用场次数填色city_layer list(zip(city_stats.index.tolist(), city_stats[场次数].astype(int).tolist())) map_chart ( Map() .add(演唱会场次, city_layer, maptypechina) .set_global_opts( title_optsopts.TitleOpts(title演唱会场次地区分布), visualmap_optsopts.VisualMapOpts(max_100) ) ) map_chart.render(output/city_map.html)这里最容易踩的坑是城市名称格式。maptypechina 的地图数据要求省份或直辖市全名带市或省比如北京市、四川省如果你的数据只有北京地图上会缺色。解决办法是在构造 city_layer 时做一层映射province_map {北京: 北京市, 上海: 上海市, 广东: 广东省} city_layer [[province_map.get(c, c), v] for c, v in city_layer]WordCloud 词云展示艺人出现频次word_data df[艺人].value_counts().head(30) wordcloud ( WordCloud() .add(, list(word_data.items()), word_size_range[16, 80], shapecircle) .set_global_opts(title_optsopts.TitleOpts(title艺人演唱会频次词云)) ) wordcloud.render(output/artist_wordcloud.html)词云适合放在大屏右下角或首页用来回答谁最爱开演唱会。shape 参数可以改成 diamond、triangle但 circle 最稳。最后用 Page 把多个图合成一张大屏page Page(page_title演唱会数据分析大屏) page.add(bar, map_chart, wordcloud) page.render(output/dashboard.html)Page 会把所有图按顺序纵向排列打开 html 后可以滚动查看。如果需要更复杂的布局用 Grid 组合每个 Grid 控制宽高和位置。大屏的标题、图表数量不要贪多三到四个图足够撑起一场答辩放太多反而显得堆砌。4.3 一键跑通一个函数保存所有分析和图表大作业源码最忌讳东一榔头西一棒子写一个入口函数运行时自动生成所有图表和 CSV是让老师眼前一亮的结构。我通常这样组织from pathlib import Path def run_analysis(df, output_diroutput): out Path(output_dir) out.mkdir(exist_okTrue) # 数据清洗 df[日期DT] df[日期].apply(parse_date) df[[最低价, 最高价, 票价均值]] df[票价区间].apply(lambda x: pd.Series(parse_price(x))) df df.dropna(subset[日期DT, 票价均值]) # 分析结果导出 monthly.to_csv(out / 月度趋势.csv, encodingutf-8-sig) city_stats.to_csv(out / 城市统计.csv, encodingutf-8-sig) price_dist.to_csv(out / 票价档位分布.csv, encodingutf-8-sig) # 绘图... fig.savefig(out / 月度趋势.png, dpi200, bbox_inchestight) bar.render(str(out / city_bar.html)) map_chart.render(str(out / city_map.html)) # ... return out用 pathlib.Path 处理路径避免字符串拼接时反斜杠出问题。CSV 导出用 utf-8-sig 编码这样用 Excel 打开不会乱码这是一个很多人不知道的细节。入口函数返回输出目录主程序里只需要调用 run_analysis(df)代码结构就清晰了。5. 大作业避坑/常见问题/排查从数据到答辩的 5 个典型坑5.1 中文乱码图里全是方块坐标轴文字不显示现象用 matplotlib 画图标题、坐标轴标签全是方块或者报错Glyph 缺失。原因matplotlib 默认字体是 DejaVu Sans不支持中文字符。很多教程只写一两行字但你换了平台就踩坑。解决绘图前必须设置中文字体。plt.rcParams[font.sans-serif] [SimHei] # Windows plt.rcParams[axes.unicode_minus] False如果你在 macOS 上跑SimHei 不存在可以改成plt.rcParams[font.sans-serif] [PingFang SC]更稳的办法是使用 seaborn 的 set_theme 里指定 font 参数。sns.set_theme(stylewhitegrid, fontSimHei) 一次设置全局字体。检查当前系统可用中文字体可以执行下面的命令import matplotlib.font_manager as fm fonts [f.name for f in fm.fontManager.ttflist if Hei in f.name] print(fonts)这条命令能列出所有含 Hei 的字体名找不到就说明系统没装中文字体去系统字体目录安装。这个坑几乎每个人都踩早发现早解决。5.2 日期解析失败to_datetime 抛异常或全是 NaT现象pd.to_datetime 对2024-05-18 周六这种字符串解析报错或者返回一堆 NaT导致后面 resample 没了数据。原因日期字符串里混了星期、时间、延期等额外字符且格式不统一也有的数据是数字格式比如20240518会被当成整数。解决清洗函数里先切分再指定格式。def parse_date(raw): s str(raw).split( )[0].replace(/, -) return pd.to_datetime(s, format%Y-%m-%d, errorscoerce)对20240518这种纯数字要先转成标准格式def parse_date(raw): s str(raw).strip() if s.isdigit() and len(s) 8: s f{s[:4]}-{s[4:6]}-{s[6:]} return pd.to_datetime(s, errorscoerce)还有一点如果数据里有待定、时间另行通知to_datetime 会识别的很难看建议清洗前先过滤df df[~df[日期].str.contains(待定|另行通知, naFalse)]排查时不要只看缺失值数量把 isna() 为 True 的记录打印出来看原始字符串长什么样这样才能对症下药。5.3 merge 之后行数翻倍或出现重复记录现象两个 DataFrame merge 后行数从 600 变成 1200 或更多分析结果明显不对。原因关联字段在右表中不唯一。比如场馆表里国家体育场出现了两行可能是不同年份容量不同merge 是笛卡尔积展开每条左表记录会匹配到多条右表记录。解决先检查关联字段是否唯一print(venue_info[场馆].duplicated().sum()) venue_info_dedup venue_info.drop_duplicates(subset场馆, keepfirst)如果确实需要多行信息比如不同年份的容量那就把年份也加进 merge 条件df_merged df.merge(venue_info, on[场馆, 年份], howleft)merge 完再核对行数assert len(df_merged) len(df), 合并后行数不一致检查关联字段的唯一性这个 assert 放在 merge 之后一旦出错立刻暴露是防止数据翻倍的好习惯。大作业里数据量小行数翻倍可能看不出来但算上座率时分子分母对不上图表数值就会很奇怪。5.4 Pyecharts 地图白屏或地区不显示颜色现象pyecharts 的 Map 页面打开后地图轮廓正常但某些区域没有颜色或者提示数据不合法。原因城市名称和地图包内置名称不匹配。maptypechina 用的是中国省级行政区划名比如北京市、广东省而你的数据里是北京、广东。解决统一做名称映射。city_name_map { 北京: 北京市, 上海: 上海市, 天津: 天津市, 重庆: 重庆市, 广东: 广东省, 四川: 四川省, 浙江: 浙江省 } mapped_data [[city_name_map.get(city, city), value] for city, value in city_data]如果地图上某个省份一直显示灰色先检查该省份名是否在映射字典里。还有一个容易忽略的问题pyecharts 需要联网加载地图文件如果答辩教室断网地图会白屏。稳妥的做法是提前把 html 在本地打开验证一次或者把地图也截图保存一份 PNG 放在报告里备用。担心版本问题的话map 的 add 方法里 maptype 参数不要写错验证可用的组合再全量跑。5.5 源码里写死绝对路径换电脑跑就崩现象在自己电脑上运行正常拷贝到实验室或答辩机器上报错 FileNotFoundError读取不到数据文件。原因代码里写了 C:\Users\你的名字\Desktop\演唱会.csv 这种绝对路径。换电脑后目录结构不同路径当然失效。解决所有文件操作都基于脚本所在目录。from pathlib import Path BASE_DIR Path(__file__).resolve().parent DATA_DIR BASE_DIR / data OUTPUT_DIR BASE_DIR / output df pd.read_csv(DATA_DIR / concerts.csv)用 Path(file).resolve().parent 拿到代码文件所在目录再拼数据文件名这样整个项目打包成一个文件夹后无论在哪个机器上运行都能找到资源。还有一个细节读取中文 CSV 时要指定 encodingutf-8-sig否则用 pandas 读出来中文乱码。答辩前最后检查一遍把项目文件夹干净打包删掉 pycache 和临时文件老师体验会好很多。6. 把源码变成过答辩的作品验证方法、报告结构与三个加分技巧6.1 结果验证怎么确认你没有算错提交前最怕数据分析结果有硬伤。我习惯做三步验证第一随机抽样核对。sample df.sample(10, random_state7) print(sample[[日期DT, 城市, 票价均值]])抽出来的记录和原始表格逐条对照日期格式、城市名、票价区间确认无误。第二计算口径复核。用 groupby 算出的总场次数自己用 value_counts 再算一遍两数对得上才放心。第三做边界测试。把某个极端值去掉比如删掉最高票价那条看均值和图表变化是否符合预期如果变化异常剧烈说明数据里有离群点需要说明。6.2 报告结构让老师 10 分钟看懂你在做什么答辩报告建议按这个结构走每一部分都有明确落点报告章节重点内容时长项目背景与目标说明数据来源、分析维度1 分钟数据清洗过程展示原始数据到 DataFrame 的处理逻辑2 分钟分析结果时间趋势、城市分布、票价结构4 分钟可视化展示静态图与交互大屏2 分钟结论与反思三个核心结论说清统计口径1 分钟核心结论不要超过三个多了记不住。比如演唱会集中在头部城市暑期和年末是办演出的旺季国际艺人票价天花板明显更高每个结论配一张图逻辑闭环。6.3 三个加分技巧第一个技巧在报告中放一张数据清洗前后对比表左边是原始脏数据右边是清洗后的标准格式这让老师一眼看到你的处理能力。第二个技巧用 pyecharts 的 Timeline 做一个按年份切换的柱状图交互式展示场次变化比静态多图更有记忆点。第三个技巧把源码结构整理清楚src 目录放脚本data 放数据output 放生成图表README 写运行步骤做到双击一个命令就能跑完全部流程。我自己做类似课题时最深刻的一条教训是永远不要把生成图表的代码和数据分析混在一长段脚本里越到后面越难改。把清洗、分析、绘图拆成三个函数出问题能快速定位。这次整理的内容就是一个可以直接参照的模板你照着搭出项目骨架把数据换一换图表参数调一调就能得到一份完整的 Python 大作业作品。希望帮到你。本文还有配套的精品资源点击获取
返回列表