资讯详情

资讯详情

NBA球员数据可视化分析:Python与K-Means聚类实战

简介基于Python的NBA球员数据可视化分析项目面向毕业设计、期末大作业与课程设计场景围绕球员得分、热点趋势等数据进行采集、清洗与可视化展示。代码附有详细注释即使Python新手也能快速理解逻辑部署后即可运行曾被导师认可为高分项目。资源包共20个文件涵盖6个Python脚本、4个CSV数据文件、3个XML配置文件以及答辩PPT、README说明等文档压缩包大小约23.57MB目录结构清晰。已有74人学习下载。项目内置数据爬虫、K-Means聚类、雷达图展示、得分分析等核心功能模块从数据获取到图表输出链路完整适合直接作为毕设整体方案或在此基础上扩展二次开发界面美观、操作简便实际应用价值较高。1. 数据可视化不是画图NBA球员项目能给你什么拿到这份基于 Python 的 NBA 球员数据可视化分析项目时我第一反应是翻代码量。文件里躺着七个 py 脚本、两份 CSV 和一个 README这不是那种「给你一个爬虫然后画两张图」的作业而是一条完整的链路热词爬虫抓数据 → CSV 落盘 → K-Means 聚类 → 雷达图输出 → 答辩 PPT 整理。对我这种经常接毕设辅导的人来说最值钱的是它把「数据分析」和「可视化」两个课程设计里的高频考核点同时覆盖了一个项目交两门作业是完全可行的。适合三类人准备 Python 方向毕设的学生、想把数据分析和爬虫整合成完整作品的全栈初学者、以及需要一套能跑通的代码做二次开发的一线开发者。项目本身不是黑匣子每个脚本都带注释跟着跑一遍就能理解数据是怎么从采集变成最终那张杜兰特雷达图的。2. 拆解项目结构七个 py 脚本和两份 CSV 的分工2.1 文件清单与模块定位我不急着跑代码先把压缩包里的东西摊开看。.zip根目录下有Basketball.py、K-Means.py、DurantScore.py、RadarMap.py、DurantRadarMap.py、SpiderHot.py六个核心脚本加上.idea里的工程配置和README.md。细看命名就能摸清作者的思路SpiderHot.py负责抓数据K-Means.py负责任务一聚类DurantScore.py和RadarMap.py负责把结果可视化成得分曲线和雷达图DurantRadarMap.py是针对杜兰特的专项可视化。文件职责猜测输出SpiderHot.py爬取球员热词与基础数据CSV 落盘K-Means.py球员数据聚类分析聚类结果与控制台输出DurantScore.py杜兰特得分数据分析得分趋势图RadarMap.py通用雷达图绘制多维度球员能力图DurantRadarMap.py杜兰特专属雷达图单球员能力图Basketball.py综合调度或数据清洗中间数据ScoreFouth.csv / Kurant.csv清洗前后数据快照数据源这种命名习惯我觉得很贴近学生项目实际——先写独立功能脚本调试最后再靠 README 串起来。.idea是 PyCharm 的工程配置说明作者开发环境就是 PyCharm你拿到后直接用 PyCharm 打开根目录就能复用他的运行配置省去手动配解释器的功夫。2.2 数据字段与清洗逻辑CSV 文件是理解整个项目的数据地基。ScoreFouth.csv从文件名猜测是第四场得分数据Kurant.csv大概率是「Kurant」——这其实是作者对 Durant 的拼写变体项目里也有Kurantttt.csv这种手滑多打 t 的版本里面存的是杜兰特相关数据。我一般拿到陌生 CSV 会先做三件事看行数、看列名、看是否有空值。import pandas as pd df_score pd.read_csv(ScoreFouth.csv) df_kurant pd.read_csv(Kurant.csv) print(df_score.shape, df_kurant.shape) print(df_score.columns.tolist()) print(df_kurant.columns.tolist()) print(df_score.isnull().sum()) print(df_kurant.isnull().sum())这段代码的作用是快速建立数据体检报告。shape告诉我们每个 CSV 的规模columns.tolist()返回字段名列表isnull().sum()按列统计空值数量。实际跑下来常见情况是得分表有 30 行左右、每行对应一场比赛的得分、篮板、助攻、抢断、盖帽、失误六个字段而球员能力表会有八到十个维度列直接喂给聚类和雷达图。有一点要注意这种学生项目的 CSV 通常不是爬虫原样输出的而是经过手动补全或拼接的中间产物。我拿到后习惯先跑一遍 describe 看数值范围如果发现某列最大最小值异常优先怀疑是字符串混入数值列处理方式是把pd.to_numeric(errorscoerce)套上去统一转格式这个操作在后面的 K-Means 之前是必须做的。3. K-Means 球员聚类从参数选择到分类结果3.1 K-Means.py 核心逻辑与 k 值选择整个项目里技术含量最高的就是K-Means.py。NBA 球员数据分析里做聚类通常目标是把球员按「得分、篮板、助攻、效率」等维度分成几类核心得分手、蓝领内线、组织后卫、角色球员。K-Means 在这里的意义不是预测而是给教练或球探一个快速分组视角这在课程设计答辩时特别好讲故事。import pandas as pd from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler import matplotlib.pyplot as plt # 读取清洗后的球员数据假设列名为 score/rebound/assist df pd.read_csv(Kurant.csv) features df[[score, rebound, assist]].apply(pd.to_numeric, errorscoerce) features features.dropna() # 标准化消除量纲差异K-Means 对距离敏感 scaler StandardScaler() X_scaled scaler.fit_transform(features) # 肘部法则选 k记录不同 k 的 SSE sse [] for k in range(2, 8): model KMeans(n_clustersk, random_state42, n_init10) model.fit(X_scaled) sse.append(model.inertia_) plt.plot(range(2, 8), sse, markero) plt.xlabel(k) plt.ylabel(SSE) plt.title(Elbow Method for Optimal k) plt.savefig(elbow.png)这段代码里最容易被忽略的是StandardScaler。K-Means 基于欧氏距离计算相似度得分字段数值可能是 20 到 30助攻只有 3 到 10不标准化的话得分字段会完全主导距离计算聚类结果直接失真。这是学生项目里最常见的翻车点我见过不少人没做标准化就聚类出来的图分群边界全靠得分一条轴撑着。n_init10是 K-Means 的多次初始化参数因为算法初始质心随机跑一次可能落到局部最优设成 10 意味着独立跑 10 次取最优是稳定的常规操作。random_state42是为了可复现答辩时要能复现结果就得固定随机种子。肘部法则画出来的图横轴 k 从 2 到 7看 SSE 下降速率的变化点如果发现没有明显拐点就直接定为 3 或 4对应「明星球员/角色球员/边缘球员」或「后卫/锋线/内线」这种语义清晰的解释。3.2 雷达图脚本把聚类结果变成可视化RadarMap.py解决的是聚类之后的呈现问题。K-Means 输出的是分组标签一堆数字很难让答辩老师直观理解雷达图可以把球员的多维度能力围成一个多边形——得分能力强、篮板弱、助攻中等图上一眼就看得出来。代码核心是用 matplotlib 的极坐标投影画闭合多边形。import matplotlib.pyplot as plt import numpy as np # categories: 雷达图的维度标签 categories [得分, 篮板, 助攻, 抢断, 盖帽, 效率] values [28.5, 7.2, 5.1, 1.4, 1.1, 24.3] # 首尾相接让雷达图闭合 values values[:1] angles np.linspace(0, 2 * np.pi, len(categories), endpointFalse).tolist() angles angles[:1] fig, ax plt.subplots(figsize(6, 6), subplot_kwdict(polarTrue)) ax.fill(angles, values, colorred, alpha0.25) ax.plot(angles, values, colorred, linewidth2) ax.set_xticks(angles[:-1]) ax.set_xticklabels(categories) ax.set_ylim(0, 35) plt.title(Player Ability Radar) plt.savefig(radar.png, dpi300)要点是angles的计算。雷达图的本质是极坐标图每个维度在圆周上占据一个等间距角度np.linspace(0, 2*np.pi, len(categories), endpointFalse)生成的就是这些角度。values values[:1]和angles angles[:1]是为了闭环——多边形要回到起点否则图形会缺一条边。alpha0.25让填充色半透明多个球员叠加时可以避免互相完全遮挡。DurantRadarMap.py和RadarMap.py的区别我判断就是把values换成杜兰特的具体数据可能是从DurantScore.py的分析结果读取或硬编码的。实际做对比时更推荐把多个球员的值装进循环同一个雷达图上叠三条折线用不同颜色区分答辩时对比效果比单球员单图强得多。3.3 聚类和可视化脚本怎么串起来我试着把执行顺序理了一遍。最合理的工作流是这样先用SpiderHot.py或直接用已有 CSV 拿到原始数据跑Basketball.py做数据清洗和字段规整输出ScoreFouth.csv这类中间表接着K-Means.py读取清洗后的数据标准化后聚类并输出分组最后RadarMap.py读聚类后的分组特征均值为每类球员画雷达图。这套链路在 README 里应该有对应说明如果 README 写得比较简略你就按这个顺序自己走一遍。这里有个实用的判断方法看每个脚本顶部的import和文件读写语句就能确认它读哪个 CSV、输出什么格式。比如K-Means.py如果直接pd.read_csv(Kurant.csv)说明作者已经把杜兰特数据作为样本集合来聚类了那DurantRadarMap.py很可能就是读同一个文件然后画单个球员。理解了这个依赖关系你换数据源时就知道要改哪个脚本、不该动哪个脚本。4. 热词爬虫模块SpiderHot.py 的抓取与落盘4.1 抓取逻辑与字段设计SpiderHot.py是这个项目里另一个加分项。现在很多可视化课程设计只做「读 CSV 画图」能自己写爬虫抓数据的项目在答辩时说服力完全不一样。从文件名「Hot」判断这个脚本抓的是球员或球队的热词/热搜数据作用是为分析提供「场外热度」维度的补充。爬虫的常见做法是用 requests 请求一个公开数据接口解析 JSON 返回结果只抽取需要的字段。我一般会控制请求频率加time.sleep避免给目标服务器造成压力同时把异常捕获做全。import requests import csv import time def fetch_player_hotwords(player_id, max_pages3): url https://example-api.com/player_hot headers {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)} results [] for page in range(1, max_pages 1): try: params {playerId: player_id, page: page} resp requests.get(url, paramsparams, headersheaders, timeout10) data resp.json() for item in data.get(data, []): results.append({ player_id: player_id, hot_word: item.get(word, ), heat: item.get(heat, 0), trend: item.get(trend, 0) }) except Exception as e: print(fpage {page} error: {e}) break time.sleep(1) # 控制频率防止被封 return results # 示例抓取杜兰特的热词并落盘 hot_data fetch_player_hotwords(durant, max_pages2) with open(hot_words.csv, w, newline, encodingutf-8) as f: writer csv.DictWriter(f, fieldnames[player_id, hot_word, heat, trend]) writer.writeheader() writer.writerows(hot_data)这段代码的逻辑分三层。第一层是构建请求参数球员 ID 和分页页码分页的目的是避免一次性拉全量数据导致响应超时第二层是解析先把 JSON 里的data列表抽出来再逐条提取word、heat、trend三个字段这里的heat可以理解为热词热度值trend是热度涨跌方向第三层是容错单页失败就打印错误并中断因为热词数据是顺序无关的少了下一页只影响完整性不影响主流程。encodingutf-8必须加否则写中文热词到 CSV 后Excel 打开会乱码。newline是 Python csv 模块的经典坑不加的话写入时每行后会多一个空行这在 pandas 里不碍事但用文本编辑器看会很难受。要提醒一点爬虫部分涉及目标网站的可访问性建议用公开数据源并在合法合规的前提下使用项目演示时用本地 CSV 就足够了。4.2 stdout 输出与本地落盘我注意到压缩包里有SpiderHot.cpython-39.pyc这个编译缓存文件说明作者是用 Python 3.9 跑的。.pyc文件不需要提交到项目里但它暴露了运行环境版本对你配置环境有参考价值。.gitignore文件的存在也很有意思说明作者是用 git 管理这个项目的你拿到后可以git init重新初始化版本控制方便自己改代码时留后悔药。爬虫跑完之后的落盘策略我建议做成双通道既写 CSV 留档也把可视化需要的关键指标直接打印到控制台。原因是课程设计答辩时老师会问「你抓到的数据长什么样」你现场跑一次脚本终端输出比打开文件更快。如果需要你把采集数据接入可视化流程直接把 CSV 路径传给K-Means.py就能串起来两个模块之间靠文件解耦这也是学生项目里比较稳的接口设计。5. 环境配置与常见问题排查避坑5.1 Python 环境与依赖安装拿到项目第一步永远是配环境不是我啰嗦是这东西真能卡人半小时。项目基于 Python 3.9 开发.pyc暴露的版本我建议你装 Python 3.9 或 3.10PyCharm 直接用社区版就够。依赖只有核心的 pandas、scikit-learn、matplotlib、requests没有 Flask 没有 Django这套组合对新手很友好。python -m venv venv source venv/bin/activate # Windows: venv\Scripts\activate pip install pandas scikit-learn matplotlib requests第一行创建虚拟环境第二行激活第三行装依赖。虚拟环境的意义是隔离项目依赖避免你机器上的其他项目和这个项目的 numpy 版本互相打架——我用 Anaconda 时代被版本冲突折腾过太多次现在任何项目一律先venv。Windows 下激活命令是venv\Scripts\activatemacOS/Linux 用source venv/bin/activate。装依赖时如果 sklearn 安装特别慢通常是网络问题国内镜像加速即可。装完之后验证方式很直接命令行里python -c import pandas, sklearn, matplotlib, requests不报错就说明环境通了。不要跳过这步直接跑主脚本否则报错时你分不清是环境问题还是代码问题。5.2 避坑记录常见的五个翻车点我自己跑这种学生项目总结了几条高频报错和解决办法按「现象 → 原因 → 解决」列出来。第一ModuleNotFoundError: No module named sklearn。现象是运行 K-Means.py 直接报错。原因是只装了 pandas 和 matplotlib没装 scikit-learn。解决执行pip install scikit-learn注意 scikit-learn 的包名是scikit-learn但 import 语句是import sklearn别写错了。第二K-Means 报ValueError: input contains NaN。现象是聚类运行中断提示数据里有空值。原因是 CSV 里有空行或爬虫没抓到部分字段dropna()没覆盖到所有列。解决读 CSV 后执行df df.dropna(subset[score, rebound, assist])只保留聚类需要的列非空的样本而不是盲目删整行。盲目dropna()可能把本来有用的样本删掉后面的雷达图会少很多数据点。第三雷达图中文乱码。现象是图形里中文标签变成方框。原因是 matplotlib 默认字体不支持中文标题和坐标轴全挂了。解决代码里加两条设置强制使用系统中文字体。import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei] plt.rcParams[axes.unicode_minus] False第二行axes.unicode_minus很关键不设的话雷达图纵轴或坐标系里的负号也会变方块。macOS 上把SimHei换成PingFang SCLinux 换成WenQuanYi Zen Hei。第四CSV 写入后 Excel 打开乱码。现象是热词文件用 Excel 看是一堆乱码。原因是encodingutf-8下 Excel 默认按 ANSI 解析。解决写入时改用utf-8-sig它会自动加 BOM 头Excel 就能正确识别。Python 的utf-8-sig就是为这个场景设计的。第五K-Means.py画出肘部图后没有明显拐点。现象是 SSE 曲线平滑下降选不出 k。原因是指标维度之间相关性太高或者数据本身就适合 2 类/4 类。解决不要死磕拐点k 值直接设为球员位置数后卫/锋线/中锋3再画聚类散点图看分群是否合理空间越分散说明 k 越合适。答辩时明确说「根据业务场景选择 k3」比硬套肘部法则更让老师信服。6. 进阶玩法换数据源、调参数、让答辩更出彩6.1 换球员与调参的核心改动点这个项目最方便的地方是换一个球员只需要改两个文件的几行代码。以杜兰特换成库里为例改动点是这样DurantScore.py里的数据读取和清理逻辑读取的是Kurant.csv升级做法是做一个通用读取函数把球员名作为参数传入不再写死文件名。import pandas as pd def load_player_data(player_name): file_map {durant: Kurant.csv, curry: curry_data.csv} path file_map.get(player_name, f{player_name}_data.csv) df pd.read_csv(path) df.columns [c.lower().strip() for c in df.columns] return df scaled_df load_player_data(curry) print(scaled_df.head())这里的关键是file_map字典做文件名映射新球员加一行curry: curry_data.csv就能生效。我会额外加一层列名标准化lower().strip()去掉空格和大小写差异因为不同来源的 CSV 列名经常是「得分」「Score」混着来不统一后续df[score]取列必炸。这是被坑过之后的血泪经验。聚类参数方面K-Means.py里最值得动的两个参数是n_clusters和random_state。random_state改成不同固定值如 7 或 100会得到不同但可复现的分群结果答辩时可以故意跑两次对比说明「初始化对结果有影响」。n_init默认值改成n_initauto在 sklearn 1.4 以上版本会自动选择迭代次数但为了兼容性还是保持数字更稳。6.2 验证聚类质量与答辩可视化技巧一个我始终觉得学生项目里缺少的操作是聚类验证。答辩时老师很可能问「你这个分群靠谱吗」你答不上来就很被动。Silhouette Score轮廓系数是检验聚类效果最简单直接的指标范围 -1 到 1越接近 1 说明同类紧凑度越高、不同类分隔越明显。from sklearn.metrics import silhouette_score # 假设已经跑完 K-Means 并获得 labels sil_avg silhouette_score(X_scaled, labels) print(fSilhouette Score: {sil_avg:.3f})拿到结论后再做一步图表升级。雷达图改成子图对比模式在同一个 Figure 里排列 3 个子图每个子图画一类的均值雷达图。答辩时把标准化的数据也保留在附注里老师问「这些维度为什么能代表球员能力」你就可以回答「数据来自公开比赛统计分析前做了 Z-score 标准化以消除量纲差异」——这句话是我见过导师点头率最高的。从那以后我每次拿到别人的可视化项目不管是不是毕设都会强制走一遍完整流程先读 README 确认依赖和执行顺序再检查 CSV 是否包含空值和重复行然后跑通主脚本最后看一眼输出图标是否带中文乱码。这几个步骤做完基本就能判断一个项目是能跑的作品还是理论摆设。希望帮到你这套流程拿去验收任何 Python 可视化项目都实用。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →