ARTICLE DETAIL

资讯详情

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

Python NBA球员数据可视化分析:从数据清洗到雷达图与热力图实战

Python NBA球员数据可视化分析:从数据清洗到雷达图与热力图实战 简介这份资源是面向Python初学者与数据分析入门者的NBA球员数据可视化分析项目源码适合用作课程设计、期末大作业或自学练手。项目基于Python搭建结合数据清洗、统计分析与图表展示帮助读者理解从原始球员数据到可视化结论的完整流程。压缩包共36个文件约288KB包含9个py源码文件、7个pyc编译文件、5个html与5个js前端页面、3个xml配置、1个sql数据脚本及readme说明等涵盖数据模型、接口模块、模板视图与静态资源目录结构清晰便于按模块阅读与二次修改。目前已有1043人学习下载说明其参考价值得到一定认可。项目经过严格调试评审分达到95分以上小白也可放心运行读者可据此掌握数据读取、指标计算、图表绘制与Web展示的实践思路并借鉴其代码组织方式完成自己的分析类作业。1. 从一份 NBA 球员数据压缩包说起为什么可视化分析值得你花一个周末跑通你手头如果有一个叫「基于python的NBA球员数据可视化分析.zip」的压缩包打开之前先别急着双击运行。这类项目在网盘和代码分享站里流通量极大但真正能跑通、能改、能讲清楚每一行在干什么的十份里不超过三份。它本质上是一个用 Python 把 NBA 球员赛季统计表读进来、清洗掉脏数据、再用 matplotlib 或 seaborn 画出得分分布、命中率热力图、球员能力雷达图的完整小流水线。适合谁适合刚学完 pandas 基础、想找一个真实数据集练手的人也适合做课程设计、期末大作业、面试作品集需要一块能讲的东西的人。它不解决业务问题但它能让你第一次完整走完「读数据 → 洗数据 → 算指标 → 出图 → 调样式」这条链路而这条链路恰恰是后面做任何数据分析都绕不开的骨架。热搜里 python 数据分析与可视化、python 爬虫可视化界面这些词能反复出现说明大量人卡在「有数据但不知道怎么变成图」这一步这个项目就是冲着这一步来的。2. 拆开压缩包之前先搞清楚 NBA 球员数据长什么样、可视化要选哪条路2.1 球员赛季统计表的典型字段与脏数据形态NBA 球员数据最常见的来源是 Basketball-Reference 或 Kaggle 上的赛季汇总表字段一般包括球员姓名、球队、位置、出场数、场均得分、篮板、助攻、抢断、盖帽、投篮命中率、三分命中率、罚球命中率、真实命中率等。原始表里几乎一定会有下面几类脏数据球员姓名带星号或脚注标记、球队字段出现「TOT」表示赛季中被交易、命中率字段是空字符串而不是 NaN、位置字段写成「PG-SG」这种复合值。如果你直接pd.read_csv然后df.describe()大概率会看到命中率列被当成 object 类型后面画图直接报错。所以第一步不是画图是确认字段类型和缺失情况。import pandas as pd # 读入时先把明显是缺失的标记统一成 NaN df pd.read_csv(nba_players.csv, na_values[, N/A, —]) # 看每列的类型和非空数量重点盯命中率列 print(df.dtypes) print(df.isnull().sum()) # 命中率列如果是 object说明混进了非数字字符 if df[FG%].dtype object: df[FG%] pd.to_numeric(df[FG%], errorscoerce)这段代码的逻辑是先让 pandas 把常见缺失标记识别为 NaN再检查类型。errorscoerce的作用是遇到无法转换的值直接变成 NaN而不是抛异常中断。参数上唯一需要你改的是文件名和列名列名要和你实际 CSV 的表头完全一致大小写和百分号都不能差。2.2 可视化路线选型matplotlib 打底还是 seaborn 提速很多人一上来就纠结用哪个库。我的建议是分布类图用 seaborn因为它一行sns.histplot就带核密度曲线需要精细控制坐标轴、标注、多子图拼版时回到 matplotlib。雷达图、热力图这类没有现成高级封装的直接用 matplotlib 的polar和imshow。不要为了炫技去上 plotly除非你确定要交互式网页输出否则导出静态图时 plotly 的依赖体积和字体问题会让你多花两小时。热搜里 python 画图横坐标太密集这个问题在球员姓名做横轴时几乎必然出现解决办法在 2.3 里说。2.3 用 pandas matplotlib 跑通第一张得分分布图先做一张最不容易翻车的图场均得分分布直方图。它能立刻告诉你数据里有没有异常值比如某球员场均 50 分但只打了 1 场。import matplotlib.pyplot as plt import seaborn as sns # 过滤掉出场数太少的样本避免极端值干扰分布 df_plot df[df[G] 20].copy() plt.figure(figsize(10, 6)) sns.histplot(df_plot[PTS], bins30, kdeTrue, color#2b6cb0) plt.title(NBA 球员场均得分分布出场≥20场) plt.xlabel(场均得分) plt.ylabel(球员人数) plt.tight_layout() plt.savefig(pts_dist.png, dpi150) plt.show()G 20这个阈值是我一般会设的低于 20 场的样本统计意义太弱会把分布尾巴拉得很长。bins30是经验值数据量在几百条时 30 个箱子既能看出形状又不会太碎。dpi150保证导出图在文档里不糊。如果你发现横轴标签重叠把plt.xticks(rotation45)加在tight_layout之前。3. 把球员能力画成雷达图和热力图指标归一化与配色参数怎么定3.1 雷达图前必须做的 min-max 归一化雷达图把得分、篮板、助攻、抢断、盖帽五个量纲不同的指标画在同一个半径轴上如果不归一化得分 30 和抢断 1.5 会让图形完全偏向得分轴看起来所有球员都是「得分怪物」。常见做法是对每个指标做 min-max 归一化把值压到 0 到 1 之间。from sklearn.preprocessing import MinMaxScaler metrics [PTS, TRB, AST, STL, BLK] scaler MinMaxScaler() df_norm df_plot.copy() df_norm[metrics] scaler.fit_transform(df_plot[metrics]) # 取一位球员做示例 player df_norm[df_norm[Player] LeBron James].iloc[0] values player[metrics].values.tolist()MinMaxScaler默认按列做(x - min) / (max - min)这里必须用fit_transform而不是transform因为你要用当前数据集的极值来定标尺。如果你后面要对比多个赛季记得把 scaler 保存下来复用否则每个赛季的极值不同图之间没法比。3.2 雷达图的闭合处理与角度参数雷达图最容易出错的地方是首尾不闭合画出来是个缺口多边形。解决办法是把第一个值追加到列表末尾角度用np.linspace生成并同样闭合。import numpy as np import matplotlib.pyplot as plt angles np.linspace(0, 2 * np.pi, len(metrics), endpointFalse).tolist() values values[:1] angles angles[:1] fig, ax plt.subplots(figsize(6, 6), subplot_kwdict(polarTrue)) ax.plot(angles, values, color#e53e3e, linewidth2) ax.fill(angles, values, color#e53e3e, alpha0.25) ax.set_xticks(angles[:-1]) ax.set_xticklabels(metrics) ax.set_title(球员能力雷达图, pad20) plt.savefig(radar.png, dpi150)endpointFalse让五个点均匀分布在圆周上而不是挤在起点。values values[:1]和angles angles[:1]是闭合的关键少任何一句图就有缺口。alpha0.25是填充透明度太深会盖住网格线。3.3 球队命中率热力图的配色与注释参数热力图适合展示「球队 × 投篮区域」或「球员 × 赛季」的命中率矩阵。用sns.heatmap时annotTrue会把数值写在格子里但数值多的时候会糊建议只在矩阵小于 10×10 时开。pivot df_plot.pivot_table(indexTm, columnsPos, valuesFG%, aggfuncmean) plt.figure(figsize(12, 8)) sns.heatmap(pivot, cmapRdYlGn, annotTrue, fmt.2f, linewidths0.5, cbar_kws{label: 平均命中率}) plt.title(各球队不同位置平均命中率) plt.tight_layout() plt.savefig(heatmap.png, dpi150)cmapRdYlGn是红黄绿渐变低值红高值绿符合命中率的直觉。fmt.2f控制注释保留两位小数。linewidths0.5给格子加细白线不然颜色块会连成一片。如果你的位置字段是「PG-SG」这种复合值先df[Pos] df[Pos].str.split(-).str[0]取主位置否则热力图会有几十行。4. 避坑与排查跑这类项目最容易翻车的五个地方4.1 中文标题显示成方块现象plt.title(球员得分)出来的图标题是一排方块。原因matplotlib 默认字体不含中文字形。解决在画图前设置plt.rcParams[font.sans-serif] [SimHei]macOS 上换成[Arial Unicode MS]同时plt.rcParams[axes.unicode_minus] False防止负号也变方块。如果系统没装 SimHei去 python 官网下载页找字体包不如直接用系统自带的中文字体名。4.2 球员姓名横轴挤成一团现象柱状图横轴球员名重叠到无法阅读。原因类别太多且默认不旋转。解决plt.xticks(rotation45, haright)或者只取前 15 名球员剩下的合并成「其他」。我一般会先按得分排序再取head(15)这样图有重点。4.3 命中率列被当成字符串导致画图报错现象TypeError: unsupported operand type(s) for -: str and str。原因CSV 里命中率带百分号或空字符串。解决读入时加na_values读入后用pd.to_numeric(..., errorscoerce)强转转换后df.dropna(subset[FG%])再画图。这一步不做后面所有涉及命中率的图都会崩。4.4 交易球员出现重复行现象同一球员在表里出现两次一次球队是「TOT」一次是具体球队。原因赛季中被交易。解决如果做球员级别分析保留「TOT」行并删掉具体球队行如果做球队级别分析删掉「TOT」行。判断逻辑是df[df[Tm] TOT]先看一眼有多少条再决定去留。4.5 保存图片时白边太大或分辨率不够现象导出的 PNG 四周留白多放进文档里显得小。原因savefig默认按画布大小导出。解决plt.savefig(x.png, dpi150, bbox_inchestight)bbox_inchestight会自动裁掉多余白边。dpi 低于 100 在 Word 里会糊150 是安全值。5. 让这份分析从「能跑」变成「能讲」一个批量出图函数和验证习惯到这一步图能出来了但如果你要对比十位球员的雷达图一张张改名字会疯。我一般会写一个批量函数把球员列表传进去自动出图并按名字存文件。这样你既有了可复现的脚本也有了能直接放进报告里的图集。def plot_radar(player_names, df_norm, metrics, out_dirradar_out): import os os.makedirs(out_dir, exist_okTrue) angles np.linspace(0, 2 * np.pi, len(metrics), endpointFalse).tolist() angles angles[:1] for name in player_names: row df_norm[df_norm[Player] name] if row.empty: print(f跳过{name} 不在数据中) continue values row[metrics].values.flatten().tolist() values values[:1] fig, ax plt.subplots(figsize(6, 6), subplot_kwdict(polarTrue)) ax.plot(angles, values, linewidth2) ax.fill(angles, values, alpha0.25) ax.set_xticks(angles[:-1]) ax.set_xticklabels(metrics) ax.set_title(name, pad20) fig.savefig(f{out_dir}/{name}.png, dpi150, bbox_inchestight) plt.close(fig)这个函数里plt.close(fig)很关键不关的话循环几十次后内存里堆满画布最后可能卡死。os.makedirs(exist_okTrue)保证输出目录不存在时自动建。row.empty的判断防止你传了一个拼错的名字导致后面索引报错。验证方法上我习惯在出完图后做两件事一是随机抽一张图用df_norm[df_norm[Player] name][metrics]把原始归一化值打印出来肉眼对一下图上顶点位置是否合理二是把所有输出图的文件名os.listdir(out_dir)和输入球员列表做集合比较确认没有漏图。这两个动作花不了一分钟但能挡住「图看起来对但数据接错了列」这种最隐蔽的翻车。最后说个习惯这类压缩包项目我从来不直接跑main.py而是先把数据读进来打印head()和shape确认字段和行数符合预期再往下走。血泪经验是很多包里的 CSV 是作者随手截取的几十行样例你拿它调好的参数放到完整数据上直接崩。先看数据再信代码。希望帮到你。本文还有配套的精品资源点击获取
返回列表