Python实战|用决策树实现NBA获胜球队预测

简介: Python实战|用决策树实现NBA获胜球队预测

NBA预测获胜球队

数据获取

因为疫情原因导致NBA2019-2020赛季没有进行完,所以我们使用NBA2018-2019赛季的数据进行预测,数据获取方式有下面两种:


通过网站获取

我们可以通过网站去获取任意一年的所有场次比赛数据,获取方式如下:


  1. 在浏览器中访问https://www.basketball-reference.com/leagues/NBA_2019_games.html
  2. 点击Share&more
  3. 点击Get table as CSV (for Excel)
  4. 复制连带表头的所有数据到Excel的文本文件中
  5. 依次选择每一个月份,复制不带表头的数据到上一个文件后


同时我们还需要获取上赛季积分榜的数据,获取方式如下:


  1. 在浏览器中访问https://www.basketball-reference.com/leagues/NBA_2018_standings.html
  2. 点击Expander Standings,可以看到整个赛季的战况信息
  3. 点击Export链接
  4. 复制数据并保存即可


通过GitHub获取

本文中的数据和代码已经上传到GitHub上,链接如下:https://github.com/bigdatavalley/NBA_predict


数据准备

在进行预测的算法设计之前,我们需要先进行数据的查看和整合,由于原有数据中很多的特征名称设定的不是很好,所以我们在加载数据的时候重新设定一下列名称,代码如下:

import pandas as pd
path = 'basketball.csv'
dataset = pd.read_csv(path, parse_dates=['Date'])
dataset.columns = [
    'Date', 'Start(ET)', 'Visitor Team', 'VisitorPts', 'Home Team', 'HomePts',
    'OT?', 'Score Type', 'Notes'
]
dataset.head()

运行结果如下:

25.png

我们在建立预测模型的时候通常会有一个标准,当我们的预测效果超过这个标准的时候我们就可以认为预测模型起到了作用,接下来我们来建立一个关于预测球队获胜的标准。


在NBA比赛中,通常分为主客场,当球队在主场比赛的时候往往会占据一定的优势,那么如果我们每次都预测主场球队获胜,应该也能得到不错的准确率,那么我们就可以用这个数值来当作我们的标准,代码如下:

# 提取新特征
# 统计客队得分小于主队的场次
dataset['HomeWin'] = dataset['VisitorPts'] < dataset['HomePts']
# 保留成label
y_true = dataset['HomeWin'].values
# y_true
dataset['HomeWin'].mean()

运行结果如下:

0.5907012195121951

现在我们就有了一个0.59作为标准,后面我们要保证建立的模型不低于这个准确率就可以了。


构建特征

构造特征一点一点进行,后面我们再陆续添加新的特征。


进行模型建立之前,还有一个重要的过程就是构建我们要使用的特征,第一个我们要思考的就是两只球队是否赢得了上一场的比赛,通常我们会认为赢得了上一场比赛的球队就是更厉害的。我们建立两个新的特征分别是主队/客队是否赢了上一场比赛。代码如下:

from collections import defaultdict
won_last = defaultdict(int)
dataset['HomeLastWin'] = 0
dataset['VisitorLastWin'] = 0
# 时间是无序的时候dataset.sort('Date').iterrows()
for index, row in dataset.iterrows():
    home_team = row['Home Team']
    visitor_team = row['Visitor Team']
    dataset.at[index, 'HomeLastWin'] = won_last[home_team]
    dataset.at[index, 'VisitorLastWin'] = won_last[visitor_team]
    won_last[home_team] = int(row['HomeWin'])
    won_last[visitor_team] = 1 - int(row['HomeWin'])
X_previouswins = dataset[['HomeLastWin', 'VisitorLastWin']].values
X_previouswins

运行结果如下:

array([[0, 0],
       [0, 0],
       [0, 0],
       ...,
       [0, 1],
       [1, 0],
       [1, 0]])

使用决策树

我们尝试使用简单的决策树算法进行简单的训练,并且通过交叉验证的方式获取评分。


决策树的原理:

决策树(上)

决策树(下)


代码如下:

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import cross_val_score
import numpy as np
clf = DecisionTreeClassifier(random_state=42)
score = cross_val_score(clf, X_previouswins, y_true, scoring = 'accuracy')
print('score is:{0:.1f}%'.format(np.mean(score)*100))

运行结果如下:

score is:59.1%

根据结果可以发现,当前的特征下,并没有使得我们的预测效果提高,接下来我们继续对数据和模型进行改进。


增加特征

考虑到球队获胜可能和上个赛季的战绩也有一定的关系,我们尝试加入上个赛季的数据来进行预测。

# 加入上赛季数据
standings = pd.read_excel('standings.xls')
# 建立新的特征(排名情况)
dataset['HomeTeamRanksHigher'] = 0
for index, row in dataset.iterrows():
    home_team = row['Home Team']
    visitor_team = row['Visitor Team']
    home_rank = standings[standings['Team'] == home_team]['Rk'].values[0]
    visitor_rank = standings[standings['Team'] == visitor_team]['Rk'].values[0]
    row['HomeTeamRanksHigher'] = int(home_rank > visitor_rank)
    dataset.at[index, 'HomeTeamRanksHigher'] = int(home_rank < visitor_rank)
clf = DecisionTreeClassifier(random_state=42)
X_homehigher = dataset[[
    'HomeLastWin', 'VisitorLastWin', 'HomeTeamRanksHigher'
]].values
score = cross_val_score(clf, X_homehigher, y_true, scoring='accuracy')
print('score is:{0:.1f}%'.format(np.mean(score) * 100))

运行结果如下:

score is:62.2%

很明显,我们加入上个赛季的战绩的时候,预测的准确率提升了3个百分点。


接下来我们继续加入交手的两只球队中哪一个在上一次交手中胜出的数据,代码如下:

last_match_winner = defaultdict(int)
dataset['HomeTeamWonLast'] = 0
for index, row in dataset.iterrows():
    home_team = row['Home Team']
    visitor_team = row['Visitor Team']
    teams = tuple(sorted([home_team, visitor_team]))
    home_team_won_last = 1 if last_match_winner[teams] == row[
        'Home Team'] else 0
    dataset.at[index, 'HomeTeamWonLast'] = home_team_won_last
    winner = row['Home Team'] if row['HomeWin'] else row['Visitor Team']
    last_match_winner[teams] = winner
clf = DecisionTreeClassifier(random_state=42)
X_lastwinner = dataset[[
    'HomeLastWin', 'VisitorLastWin', 'HomeTeamRanksHigher', 'HomeTeamWonLast'
]].values
score = cross_val_score(clf, X_lastwinner, y_true, scoring='accuracy')
print('score is:{0:.1f}%'.format(np.mean(score) * 100))

运行结果如下:

score is:61.7%

结果和上面差异不大,没有关系,我们继续尝试使用其他的策略来进行改进。


加入队伍数据

我们之前做的工作都是根据一些比赛数据来进行的,下面我们尝试加入队伍数据来检验一下我们的运行成果,由于我们不能直接对字符数据进行计算,所以先把数据通过LabelEncoder转化为数值类型,但是一般数值类型又会有大小造成的影响,所以我们再进行一次OneHotEncoder的操作即可。代码如下:

from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OneHotEncoder
encoding = LabelEncoder()
onehot = OneHotEncoder()
encoding.fit(dataset['Home Team'].values)
home_teams = encoding.transform(dataset['Home Team'].values)
visitor_teams = encoding.transform(dataset['Visitor Team'].values)
X_teams = np.vstack([home_teams, visitor_teams]).T
X_teams = onehot.fit_transform(X_teams).todense()
X_all = np.hstack([X_lastwinner, X_teams])
clf = DecisionTreeClassifier(random_state=42)
score = cross_val_score(clf, X_all, y_true, scoring='accuracy')
print('score is:{0:.1f}%'.format(np.mean(score) * 100))

运行结果如下:

score is:60.7%

很显然虽然比我们直接预测主队获胜的效果要好,但是也没有高出很多。不要慌,我们继续使用更好的算法来尝试一下。


使用随机森林

随机森林是一种以决策树为基分类器的集成学习算法,理论上讲,我们所得到的效果要好于决策树。

代码如下:

clf = RandomForestClassifier(random_state=42)
score = cross_val_score(clf, X_all, y_true, scoring='accuracy')
print('score is:{0:.1f}%'.format(np.mean(score) * 100))

运行结果如下:

score is:63.6%

尝试使用网格搜索,代码如下:

from sklearn.model_selection import GridSearchCV
parameter_space = {
    'max_features': [2, 10, 'auto'],
    'n_estimators': [100, 200],
    'criterion': ['gini', 'entropy'],
    'min_samples_leaf': [2, 4, 6]
}
clf = RandomForestClassifier(random_state=42)
grid = GridSearchCV(clf, parameter_space)
grid.fit(X_all, y_true)
print('score is:{0:.1f}%'.format(np.mean(score) * 100))

运行结果如下:

score is:63.6%

可以看到根据目前我们所构造的几个简单的特征就已经可以得到显著的准确率提升了。同时收到球员转会、受伤等情况的影响,对于不同赛季的数据使用这些方法会得到不同的结果,有兴趣的读者可以自己获取其他赛季的数据来尝试一下。


进一步考虑

你可能对当前的结果还不是很满意,可以尝试进行下面几个方向的参考:


  • 上一次比赛距离本次比赛的时间
  • 最近半个月的比赛状态
  • 双方在最近几场比赛的战绩
  • 每个球队在客场和主场的表现情况
相关文章
|
5天前
|
存储 前端开发 机器人
Python网络数据抓取(6):Scrapy 实战
Python网络数据抓取(6):Scrapy 实战
24 2
|
5天前
|
机器学习/深度学习 Python
【Python实战】——神经网络识别手写数字(三)
【Python实战】——神经网络识别手写数字
|
2天前
|
网络协议 Python
Python 网络编程实战:构建高效的网络应用
【5月更文挑战第18天】Python在数字化时代成为构建网络应用的热门语言,因其简洁的语法和强大功能。本文介绍了网络编程基础知识,包括TCP和UDP套接字,强调异步编程、数据压缩和连接池的关键作用。提供了一个简单的TCP服务器和客户端代码示例,并提及优化与改进方向,鼓励读者通过实践提升网络应用性能。
19 6
|
2天前
|
算法 Java Python
【Python 的内存管理机制专栏】Python 内存管理实战:性能优化与内存泄漏检测
【5月更文挑战第18天】Python内存管理关乎程序性能与稳定性。优化包括避免过多临时对象,如优化列表推导式减少对象创建。警惕循环引用造成的内存泄漏,如示例中的Node类。使用`gc`模块检测泄漏,通过`gc.set_debug(gc.DEBUG_LEAK)`和`gc.collect()`获取信息。实践中需持续分析内存使用,优化算法、数据结构和资源释放,以提升程序质量与效率。
【Python 的内存管理机制专栏】Python 内存管理实战:性能优化与内存泄漏检测
|
5天前
|
存储 缓存 监控
利用Python和Flask构建RESTful API的实战指南
在当今的软件开发中,RESTful API已成为前后端分离架构中的核心组件。本文将带你走进实战,通过Python的Flask框架,一步步构建出高效、安全的RESTful API。我们将从项目初始化、路由设置、数据验证、错误处理到API文档生成,全方位地探讨如何构建RESTful API,并给出一些实用的最佳实践和优化建议。
|
5天前
|
Python
Python自动化办公实战案例:文件整理与邮件发送
Python自动化办公实战案例:文件整理与邮件发送
11 0
|
5天前
|
存储 人工智能 测试技术
python自动化测试实战 —— CSDN的Web页面自动化测试
python自动化测试实战 —— CSDN的Web页面自动化测试
196 0
|
5天前
|
Web App开发 设计模式 测试技术
python自动化测试实战 —— 自动化测试框架的实例
python自动化测试实战 —— 自动化测试框架的实例
18 0
|
5天前
|
监控 数据可视化 IDE
python自动化测试实战 —— 单元测试框架
python自动化测试实战 —— 单元测试框架
20 2
|
5天前
|
Web App开发 JavaScript 测试技术
python自动化测试实战 —— WebDriver API的使用
python自动化测试实战 —— WebDriver API的使用
8 1