☰
Python爬虫+机器学习实战:NBA比赛数据抓取与胜负预测课程设计
2026/10/10 6:10:16 网站建设 项目流程

简介:这份资源面向计算机相关专业学生与Python初学者,提供一套可直接用于课程设计、大作业或学期项目答辩的完整方案,核心是用爬虫抓取NBA比赛数据,再借助机器学习对数据进行处理分析,最终输出比赛结果预测,属于入门到进阶之间的实战型项目。压缩包共11个文件,约311KB,包含6个csv数据文件、4个py脚本和1份docx说明文档,csv用于存放赛季赛程、球队与对手的场均及综合统计数据,py脚本分别承担数据爬取与模型预测任务,docx则记录项目使用说明。目前已有1462人学习下载,说明该方案在同类课设中具备一定参考价值。读者可获得从数据采集、特征整理到模型训练预测的完整代码链路,以及提前备好的历史赛季数据资料,便于直接运行、复现结果并在此基础上调整模型或扩展功能,适合作为课程设计参考与答辩演示素材。

1. 从一份课设包说起:爬虫抓 NBA 数据、机器学习预测胜负到底靠不靠谱

每年学期末,问「有没有能直接跑的 Python 课程设计」的人特别多,但真正能拿去答辩、还能讲清楚原理的项目其实不多。这份资源就是冲着这个痛点来的:它把「爬取 NBA 比赛数据」和「用机器学习预测比赛结果」串成了一条完整链路,包里既有nba_spider.py、nba_spider2.py、nba_spider3.py三个爬虫脚本,也有NBA.py这个建模入口,还附带了 15-16、16-17 两个赛季的对手数据、赛程、球队统计和最终结果 CSV,以及一份课程设计项目使用说明文档-readme.docx。换句话说,它不是只给你一段模型代码,而是把数据获取、清洗、特征拼接、训练预测这条线都铺好了。

适合谁?如果你正在做 Python 课程设计、机器学习大作业,或者想找一个「有真实数据、有爬虫、有模型、能讲出业务背景」的练手项目,这份资源能省掉大量找数据、对字段的时间。但先说结论:它不是一个「一键出结果」的黑匣子,数据里存在赛季跨度、主客场、背靠背等噪声,模型准确率也不会高到离谱。想拿优秀项目评选,关键不在于跑通,而在于你能不能讲清楚特征怎么选、标签怎么造、模型为什么这么调。下面我按实际拆包顺序,把这份资源从结构到落地讲透。

2. 拆开压缩包:文件清单、数据字段与建模链路怎么对应

2.1 三类文件的分工:爬虫、数据、模型入口

先把项目所需数据文件及代码.zip解压后的文件按角色分一下,不然后面很容易把「原始数据」和「特征表」搞混。

文件角色说明
nba_spider.py/nba_spider2.py/nba_spider3.py数据获取三个版本的爬虫脚本,通常对应不同页面结构或不同赛季
15-16Opponent_Per_Game_Stat.csv原始数据2015-2016 赛季对手场均统计
15-16Team_Per_Game_Stat.csv原始数据2015-2016 赛季球队场均统计
15-16Miscellaneous_Stat.csv原始数据2015-2016 赛季杂项统计
16-17Schedule.csv原始数据2016-2017 赛季赛程
2015-2016_result.csv标签来源2015-2016 赛季比赛结果
prediction of 2016-2017.csv输出/预测对 2016-2017 赛季的预测结果
NBA.py建模入口读取数据、构造特征、训练模型、输出预测
课程设计项目使用说明文档-readme.docx文档使用说明与项目背景

这里有个容易翻车的点:15-16开头的是训练侧数据,16-17Schedule.csv是预测侧赛程,2015-2016_result.csv提供历史胜负标签。也就是说,这个项目的思路是「用 15-16 赛季的统计和结果训练,去预测 16-17 赛季的赛程」。理解这条时间线,后面所有特征工程才有意义。

2.2 从原始 CSV 到特征矩阵:字段怎么拼

课程设计里最容易被老师追问的就是「你的特征从哪来」。这份资源里,球队场均统计和对手场均统计是两条互补的线:一条描述「自己打得怎么样」,一条描述「让对手打成什么样」。常见做法是把同一场比赛的主队和客队各取一行,做差或做比,形成对比特征。

我一般会先写一段探查脚本,确认字段名和缺失情况,再决定怎么拼:

import pandas as pd # 读取球队场均统计和对手场均统计 team = pd.read_csv("15-16Team_Per_Game_Stat.csv") opp = pd.read_csv("15-16Opponent_Per_Game_Stat.csv") result = pd.read_csv("2015-2016_result.csv") # 看字段、看形状、看缺失,别急着建模 print(team.columns.tolist()) print(team.shape, opp.shape, result.shape) print(team.isnull().sum().sort_values(ascending=False).head(10))

这段代码不涉及任何模型,但它是整个项目的地基。team.columns.tolist()帮你确认字段名是否带空格或特殊符号,shape确认样本量,isnull()排序后能一眼看出哪些列缺失严重。参数上没什么可调的,重点是先跑一遍再动手。如果字段名里有Unnamed: 0这种索引列,记得在读取时加index_col=0或后续 drop 掉,否则拼特征时会多出一列无意义数据。

2.3 标签构造:胜负怎么变成 0/1

2015-2016_result.csv里通常是比赛日期、主队、客队、比分。要把「预测比赛结果」变成监督学习问题,得先造标签。常见做法是主队赢记 1,主队输记 0,平局在 NBA 里基本不存在,可以忽略。

# 假设 result 里有 home_team、away_team、home_score、away_score result["label"] = (result["home_score"] > result["away_score"]).astype(int) # 检查标签分布,避免严重不平衡 print(result["label"].value_counts(normalize=True))

astype(int)把布尔值转成 0/1,value_counts(normalize=True)看正负样本比例。如果主队胜率在 55% 到 60% 之间,属于正常范围,不用做重采样;如果偏离太大,就要回头检查比分列是不是读串了。这一步的坑在于:有些结果表里主客队字段名和统计表不一致,拼特征时会对不上,建议先统一队名再合并。

3. 跑通爬虫与建模:从 nba_spider 到 NBA.py 的实操步骤

3.1 爬虫脚本怎么用:先看结构再运行

nba_spider.py、nba_spider2.py、nba_spider3.py三个脚本大概率是迭代版本,页面结构变化或抓取目标不同。直接三个都跑没必要,正确做法是先打开看请求的 URL 和解析逻辑,确认它抓的是赛程、球队统计还是比赛结果。

# 先看脚本头部依赖和请求地址,不要上来就 python nba_spider.py head -n 40 nba_spider.py grep -n "http" nba_spider.py

head看导入的库,常见是requests+BeautifulSoup或pandas.read_html;grep找请求地址,确认目标页面还在不在。如果页面结构已经变了,脚本可能返回空表或报解析错误,这时候要么改选择器,要么直接用包里已经准备好的 CSV,不必死磕爬虫。课程设计答辩时,老师更关心你懂不懂数据来源,而不是爬虫能不能实时跑通。

运行爬虫时注意加延时,别高频请求:

import time import requests headers = {"User-Agent": "Mozilla/5.0"} for url in url_list: resp = requests.get(url, headers=headers, timeout=10) # 解析逻辑略 time.sleep(2) # 控制频率,避免给目标站点造成压力

timeout=10防止请求卡死,time.sleep(2)控制访问频率。这是基本礼貌,也是避免被封的常规做法。如果脚本里没有延时,建议自己补上。

3.2 NBA.py 建模流程:读数据、拼特征、训练、预测

NBA.py是核心入口,通常包含读取 CSV、合并特征、划分训练测试集、训练模型、输出预测几段。下面给一个可复现的骨架,你可以对照原脚本改:

import pandas as pd from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import accuracy_score # 1. 读数据 team = pd.read_csv("15-16Team_Per_Game_Stat.csv") opp = pd.read_csv("15-16Opponent_Per_Game_Stat.csv") result = pd.read_csv("2015-2016_result.csv") # 2. 造标签 result["label"] = (result["home_score"] > result["away_score"]).astype(int) # 3. 拼特征(示意:按队名合并主队统计) df = result.merge(team, left_on="home_team", right_on="Team", how="left") df = df.merge(opp, left_on="away_team", right_on="Team", how="left", suffixes=("_home", "_away")) # 4. 选特征列,去掉标签和文本列 feature_cols = [c for c in df.columns if df[c].dtype != "object" and c != "label"] X = df[feature_cols].fillna(0) y = df["label"] # 5. 划分与训练 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) model = RandomForestClassifier(n_estimators=200, random_state=42) model.fit(X_train, y_train) # 6. 评估 pred = model.predict(X_test) print("accuracy:", accuracy_score(y_test, pred))

逻辑上分六步:读数据、造标签、拼特征、选列、训练、评估。参数上,test_size=0.2是常见划分比例,random_state=42保证可复现,n_estimators=200是随机森林的树数量,太少容易欠拟合,太多训练变慢。fillna(0)是简单兜底,更严谨的做法是用均值或中位数填充,并在文档里说明。注意merge时主客队要分别对应,suffixes防止同名列冲突,这是拼特征时最容易出错的地方。

3.3 预测 16-17 赛季:把赛程喂给模型

训练完之后,用16-17Schedule.csv做预测,输出到prediction of 2016-2017.csv。这一步的关键是:预测侧的特征列必须和训练侧完全一致,列名、顺序、缺失处理都要对齐。

schedule = pd.read_csv("16-17Schedule.csv") # 用同样的方式拼特征,确保列和 X 一致 X_pred = schedule.reindex(columns=feature_cols, fill_value=0) schedule["predicted"] = model.predict(X_pred) schedule.to_csv("prediction of 2016-2017.csv", index=False)

reindex(columns=feature_cols)强制对齐列,缺的补 0,多的丢掉。这一步不做,模型直接报错或预测结果错位。index=False避免多出一列索引。输出文件就是资源里那个prediction of 2016-2017.csv的来源。

4. 避坑与排查:数据、模型、环境里最容易翻车的几处

4.1 队名不一致导致合并后样本骤减

现象:merge之后行数从几百掉到几十。原因:主队字段写Golden State Warriors,统计表里写GSW或带空格。解决:先统一队名,做映射字典或str.strip()去空格,再合并。合并后打印df.shape确认样本量,掉太多就是没对上。

4.2 特征里混入标签造成准确率虚高

现象:模型准确率 95% 以上,答辩时被问就露馅。原因:特征列里不小心包含了比分、胜负等结果字段。解决:选特征前先看列名,凡是和比赛结果直接相关的列一律排除,只保留赛前可获得的统计。判断标准是「这场比赛开打之前,这个数能不能拿到」。

4.3 赛季跨度导致分布漂移

现象:训练集表现好,预测 16-17 赛季结果很离谱。原因:15-16 和 16-17 之间球队阵容、战术变化大,特征分布不一致。解决:在文档里说明这是跨赛季预测,属于难点而非 bug;可以只用赛季内数据做交叉验证,把跨赛季预测作为扩展讨论。

4.4 环境依赖缺失或版本不兼容

现象:ModuleNotFoundError或read_csv报编码错误。原因:没装pandas、scikit-learn,或 CSV 是 GBK 编码。解决:先pip install pandas scikit-learn,读取时加encoding="gbk"或encoding="utf-8-sig"试。课程设计环境建议固定 Python 3.8 及以上,避免版本差异。

4.5 爬虫目标页面结构变化

现象:爬虫返回空列表或解析报错。原因:目标站点改版,选择器失效。解决:优先使用包里已备好的 CSV 完成建模,爬虫作为数据来源说明;若必须跑通,打开页面重新定位标签,更新解析逻辑。

5. 把课设做出区分度:特征工程与结果验证的几个具体技巧

想让这份资源在答辩里脱颖而出,重点不在换更复杂的模型,而在特征和验证。我一般会先做一版基线,再逐步加特征,每加一次都记录准确率变化,这样答辩时能讲出「为什么这么选」。

第一个技巧是构造「近期状态」特征。原始统计是整个赛季的场均,但球队状态有起伏。常见做法是按日期排序,取每场比赛前 N 场的滚动平均,作为赛前状态。这样特征更贴近真实预测场景,也能体现你懂时间序列的先后关系。

# 按日期排序后,取主队近 5 场场均得分的滚动均值 df = df.sort_values("date") df["home_recent_pts"] = df.groupby("home_team")["home_score"].transform( lambda s: s.shift(1).rolling(5, min_periods=1).mean() )

shift(1)保证只用赛前数据,避免数据泄漏;rolling(5)是窗口大小,可以改成 3 或 10 做对比。这个特征加上去,模型会更稳,答辩时也有东西可讲。

第二个技巧是交叉验证代替单次划分。单次train_test_split结果波动大,换成cross_val_score更能说明模型稳定性:

from sklearn.model_selection import cross_val_score scores = cross_val_score(model, X, y, cv=5, scoring="accuracy") print(scores.mean(), scores.std())

cv=5是五折交叉验证,scores.std()看波动。标准差小说明模型稳,标准差大就要检查特征或样本划分。

第三个技巧是对比多个模型。随机森林、逻辑回归、梯度提升各跑一遍,用表格记录准确率和训练时间,答辩时展示选型依据。

模型准确率(5 折均值)训练时间备注
逻辑回归约 0.65快可解释性强,适合讲系数
随机森林约 0.68中特征重要性可输出
梯度提升约 0.69慢小样本易过拟合

具体数值以你实际跑出来的为准,这里给的是量级参考。重点是把「为什么选这个模型」讲清楚,而不是追求最高分。

最后一个习惯:每次改完特征或参数,都把结果写进一张实验记录表,包括改了什麼、准确率变化、结论。答辩前翻一遍,比临时回忆靠谱得多。从那以后我每次做课设都强制走一遍「基线—加特征—交叉验证—对比模型」的流程,避免最后只剩一个说不清来路的数字。希望这份拆解能帮你把这份资源真正用起来,顺利通过答辩。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询