您现在的位置是:首页 >其他 >大数据分析案例-基于决策树算法构建世界杯比赛预测模型网站首页其他
大数据分析案例-基于决策树算法构建世界杯比赛预测模型
?♂️ 个人主页:@艾派森的个人主页
✍?作者简介:Python学习者
? 希望大家多多支持,我们一起进步!?
如果文章对你有帮助的话,
欢迎评论 ?点赞?? 收藏 ?加关注+
喜欢大数据分析项目的小伙伴,希望可以多多支持该系列的其他文章
目录
1.项目背景
世界杯足球比赛是全球最大规模的国际足球赛事之一,吸引着数以亿计的观众。对于球迷和体育爱好者来说,预测比赛结果是一项有趣且具有挑战性的任务。足球比赛结果的预测可以帮助球迷制定投注策略、提供比赛观看的参考以及评估球队和球员的表现。
在过去的几十年中,研究人员一直致力于开发各种预测模型,以预测足球比赛结果。其中,决策树算法是一种常用的机器学习方法,已经在许多领域取得了成功应用。决策树算法通过将决策问题分解为一系列简单的决策规则,可以对复杂的数据集进行建模和预测。
在构建世界杯比赛预测模型方面,决策树算法具有一些优势。首先,决策树算法可以处理多个输入变量(如球队历史战绩、球员伤病情况、球队排名等)和离散或连续的输出变量(比赛结果)。其次,决策树模型易于理解和解释,可以帮助揭示影响比赛结果的关键因素。此外,决策树算法还可以处理缺失数据和异常值,具有较好的鲁棒性。
因此,基于决策树算法构建世界杯比赛预测模型具有一定的理论和实际意义。这一研究可以探索各种与比赛结果相关的因素,如球队实力、球队战术、球员技术等,并通过分析历史数据构建一个可靠的预测模型。这样的预测模型可以为球迷、媒体和体育分析师提供有价值的信息,帮助他们做出更准确的预测和评估。
2.项目简介
2.1项目说明
本项目旨在分析往届世界杯比赛数据,找出规律,最后使用决策树算法构建世界杯比赛预测模型,给出两个球队即可预测胜率,可以给爱看球的小伙伴提供一个参考。
2.2数据说明
本数据来源于天池数据集,共有3个csv文件,具体字段信息如下:
世界杯成绩信息表:WorldCupsSummary
包含了所有21届世界杯赛事(1930-2018)的比赛主办国、前四名队伍、总参赛队伍、总进球数、现场观众人数等汇总信息,包括如下字段:
- Year: 举办年份
- HostCountry: 举办国家
- Winner: 冠军队伍
- Second: 亚军队伍
- Third: 季军队伍
- Fourth: 第四名队伍
- GoalsScored: 总进球数
- QualifiedTeams: 总参赛队伍数
- MatchesPlayed: 总比赛场数
- Attendance: 现场观众总人数
- HostContinent: 举办国所在洲
- WinnerContinent: 冠军国家队所在洲
世界杯比赛比分汇总表:WorldCupMatches.csv
包含了所有21届世界杯赛事(1930-2014)单场比赛的信息,包括比赛时间、比赛主客队、比赛进球数、比赛裁判等信息。包括如下字段:
- Year: 比赛(所属世界杯)举办年份
- Datetime: 比赛具体日期
- Stage: 比赛所属阶段,包括 小组赛(GroupX)、16进8(Quarter-Final)、半决赛(Semi-Final)、决赛(Final)等
- Stadium: 比赛体育场
- City: 比赛举办城市
- Home Team Name: 主队名
- Away Team Name: 客队名
- Home Team Goals: 主队进球数
- Away Team Goals: 客队进球数
- Attendance: 现场观众数
- Half-time Home Goals: 上半场主队进球数
- Half-time Away Goals: 上半场客队进球数
- Referee: 主裁
- Assistant 1: 助理裁判1
- Assistant 2: 助理裁判2
- RoundID: 比赛所处阶段ID,和Stage字段对应
- MatchID: 比赛ID
- Home Team Initials: 主队名字缩写
- Away Team Initials: 客队名字缩写
世界杯球员信息表:WorldCupPlayers.csv
- RoundID: 比赛所处阶段ID,同比赛信息表的RoundID字段
- MatchID: 比赛ID
- Team Initials: 队伍名
- Coach Name: 教练名
- Line-up: 首发/替补
- Shirt Number: 球衣号码
- Player Name: 队员名
- Position: 比赛角色,包括:C=Captain, GK=Goalkeeper
- Event: 比赛事件,包括进球、红/黄牌等
2.3技术工具
Python版本:3.9
代码编辑器:jupyter notebook
3.算法原理
决策树( Decision Tree) 又称为判定树,是数据挖掘技术中的一种重要的分类与回归方法,它是一种以树结构(包括二叉树和多叉树)形式来表达的预测分析模型。其每个非叶节点表示一个特征属性上的测试,每个分支代表这个特征属性在某个值域上的输出,而每个叶节点存放一个类别。一般,一棵决策树包含一个根节点,若干个内部结点和若干个叶结点。叶结点对应于决策结果,其他每个结点对应于一个属性测试。每个结点包含的样本集合根据属性测试的结果划分到子结点中,根结点包含样本全集,从根结点到每个叶结点的路径对应了一个判定的测试序列。决策树学习的目的是产生一棵泛化能力强,即处理未见示例强的决策树。使用决策树进行决策的过程就是从根节点开始,测试待分类项中相应的特征属性,并按照其值选择输出分支,直到到达叶子节点,将叶子节点存放的类别作为决策结果。
决策树的构建
特征选择:选取有较强分类能力的特征。
决策树生成:典型的算法有 ID3 和 C4.5, 它们生成决策树过程相似, ID3 是采用信息增益作为特征选择度量, 而 C4.5 采用信息增益比率。
决策树剪枝:剪枝原因是决策树生成算法生成的树对训练数据的预测很准确, 但是对于未知数据分类很差, 这就产生了过拟合的现象。涉及算法有CART算法。
决策树的划分选择
熵:物理意义是体系混乱程度的度量。
信息熵:表示事物不确定性的度量标准,可以根据数学中的概率计算,出现的概率就大,出现的机会就多,不确定性就小(信息熵小)。
决策树的剪枝
剪枝:顾名思义就是给决策树 "去掉" 一些判断分支,同时在剩下的树结构下仍然能得到不错的结果。之所以进行剪枝,是为了防止或减少 "过拟合现象" 的发生,是决策树具有更好的泛化能力。
具体做法:去掉过于细分的叶节点,使其回退到父节点,甚至更高的节点,然后将父节点或更高的叶节点改为新的叶节点。
剪枝的两种方法:
预剪枝:在决策树构造时就进行剪枝。在决策树构造过程中,对节点进行评估,如果对其划分并不能再验证集中提高准确性,那么该节点就不要继续王下划分。这时就会把当前节点作为叶节点。
后剪枝:在生成决策树之后再剪枝。通常会从决策树的叶节点开始,逐层向上对每个节点进行评估。如果剪掉该节点,带来的验证集中准确性差别不大或有明显提升,则可以对它进行剪枝,用叶子节点来代填该节点。
4.项目实施步骤
4.1理解数据
首先导入本次实验用到的第三方库
接着加载这三个数据文件,并删除缺失值
4.2探索性数据分析
简单的分析一下世界杯的冠军情况
从图我们可看出,巴西/意大利/德国是获得冠军最多的国家。
4.3数据预处理
这里我们用德国取代德国DR和德国FR,用俄罗斯取代苏联
接着准备一个字典用来存储球队名字
删除不必要的列同时计算每支球队成为世界杯赛冠军的次数
加上“主队冠军”和“客场冠军”:获取世界杯冠军的次数
定义一个函数用于找出谁赢了:主场胜:1,客场胜:2,平局:0
将team_name字典中的团队名称替换为id
4.4特征工程
准备建模用到的X,y数据
打乱数据,然后拆分数据集为训练集和测试集
4.5模型构建
用SVM支持向量机模型进行训练并打印模型的评估指标
从结果发现SVM模型只有52%的正确率,模型效果较差,该模型应该不适合这个数据。
用决策树算法进行训练并打印模型的评估指标
换了决策树算法,模型在测试集上的正确率一下提升到82%,看来决策树算法才是最适合该数据集的,故我们最终使用决策树算法作为最终的模型选择。
4.6模型预测
为了方便预测且让结果更直观,我们自定义一个预测函数
这里我们直接用2022年的卡塔尔世界杯最后半决赛的部分来检测模型效果
先来预测英格兰对法国的比赛
可以看出模型给出的最大概率是法国赢英格兰,但是两个球队赢的概率比较接近,与真实结果一样,预测正确!
预测阿根廷对克罗地亚的比赛
可以看出模型给出的概率阿根廷赢是克罗地亚赢的三倍多,与真实结果相比较为吻合,预测正确!
预测法国对摩洛哥的比赛
可以看出模型给出的概率法国赢是摩洛哥赢的二倍多,与真实结果一样,预测正确!
预测克罗地亚对摩洛哥的比赛
可以看出模型给出的概率最大是摩洛哥赢,但是可惜是克罗地亚赢了,预测错误!
预测阿根廷对法国的比赛
可以看出模型给出的概率最大是阿根廷赢,与真实结果一样,预测正确!
通过对上面5场比赛的预测,我们可以看出有4场预测正确,概率也是接近80%,模型效果还是不错的!需要注意的是原始数据集中是没有2022年卡塔尔世界杯比赛的数据的!说明模型在预测未知比赛上准确率还是可以的。
5.实验总结
本次实验我们使用了2018年及其之前的世界杯比赛数据,通过建立决策树模型,模型准确率为82%,接着我们使用该模型预测了2022年世界杯的5场半决赛及决赛,模型准确率也是接近80%的,说明模型效果还是很不错的。
心得与体会:
通过这次Python项目实战,我学到了许多新的知识,这是一个让我把书本上的理论知识运用于实践中的好机会。原先,学的时候感叹学的资料太难懂,此刻想来,有些其实并不难,关键在于理解。
在这次实战中还锻炼了我其他方面的潜力,提高了我的综合素质。首先,它锻炼了我做项目的潜力,提高了独立思考问题、自我动手操作的潜力,在工作的过程中,复习了以前学习过的知识,并掌握了一些应用知识的技巧等
在此次实战中,我还学会了下面几点工作学习心态:
1)继续学习,不断提升理论涵养。在信息时代,学习是不断地汲取新信息,获得事业进步的动力。作为一名青年学子更就应把学习作为持续工作用心性的重要途径。走上工作岗位后,我会用心响应单位号召,结合工作实际,不断学习理论、业务知识和社会知识,用先进的理论武装头脑,用精良的业务知识提升潜力,以广博的社会知识拓展视野。
2)努力实践,自觉进行主角转化。只有将理论付诸于实践才能实现理论自身的价值,也只有将理论付诸于实践才能使理论得以检验。同样,一个人的价值也是透过实践活动来实现的,也只有透过实践才能锻炼人的品质,彰显人的意志。
3)提高工作用心性和主动性。实习,是开端也是结束。展此刻自我面前的是一片任自我驰骋的沃土,也分明感受到了沉甸甸的职责。在今后的工作和生活中,我将继续学习,深入实践,不断提升自我,努力创造业绩,继续创造更多的价值。
这次Python实战不仅仅使我学到了知识,丰富了经验。也帮忙我缩小了实践和理论的差距。在未来的工作中我会把学到的理论知识和实践经验不断的应用到实际工作中,为实现理想而努力。
源代码
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.utils import shuffle
from sklearn.metrics import classification_report, confusion_matrix
from sklearn.svm import SVC
import warnings
warnings.filterwarnings('ignore')
# 导入数据
matches = pd.read_csv('WorldCupMatches.csv')
players = pd.read_csv('WorldCupPlayers.csv')
cups = pd.read_csv('WorldCupsSummary.csv')
# 删除缺失值
matches = matches.dropna()
players = players.dropna()
cups = cups.dropna()
matches.head()
matches.head()
players.head()
# 世界杯赛冠军的数量
plt.figure(figsize=(12,6))
sns.countplot(x='Winner',data=cups)
plt.show()
# 用德国取代德国DR和德国FR,用俄罗斯取代苏联
def replace_name(df):
if(df['Home Team Name'] in ['German DR', 'Germany FR']):
df['Home Team Name'] = 'Germany'
elif(df['Home Team Name'] == 'Soviet Union'):
df['Home Team Name'] = 'Russia'
if(df['Away Team Name'] in ['German DR', 'Germany FR']):
df['Away Team Name'] = 'Germany'
elif(df['Away Team Name'] == 'Soviet Union'):
df['Away Team Name'] = 'Russia'
return df
matches = matches.apply(replace_name, axis='columns')
matches.head()
# 创建一个存储足球队的字典
team_name = {}
index = 0
for idx, row in matches.iterrows():
name = row['Home Team Name']
if(name not in team_name.keys()):
team_name[name] = index
index += 1
name = row['Away Team Name']
if(name not in team_name.keys()):
team_name[name] = index
index += 1
team_name
# 删除不必要的列
dropped_matches = matches.drop(['Datetime', 'Stadium', 'Referee', 'Assistant 1', 'Assistant 2', 'RoundID',
'Home Team Initials', 'Away Team Initials', 'Half-time Home Goals', 'Half-time Away Goals',
'Attendance', 'City', 'MatchID', 'Stage'], 1)
# 计算每支球队成为世界杯赛冠军的次数
championships = cups['Winner'].map(lambda p: 'Germany' if p=='Germany FR' else p).value_counts()
championships
# 加上“主队冠军”和“客场冠军”:获取世界杯冠军的次数
dropped_matches['Home Team Championship'] = 0
dropped_matches['Away Team Championship'] = 0
def count_championship(df):
if(championships.get(df['Home Team Name']) != None):
df['Home Team Championship'] = championships.get(df['Home Team Name'])
if(championships.get(df['Away Team Name']) != None):
df['Away Team Championship'] = championships.get(df['Away Team Name'])
return df
dropped_matches = dropped_matches.apply(count_championship, axis='columns')
dropped_matches.head()
# 定义一个函数用于找出谁赢了:主场胜:1,客场胜:2,平局:0
dropped_matches['Winner'] = '-'
def find_winner(df):
if(int(df['Home Team Goals']) == int(df['Away Team Goals'])):
df['Winner'] = 0
elif(int(df['Home Team Goals']) > int(df['Away Team Goals'])):
df['Winner'] = 1
else:
df['Winner'] = 2
return df
dropped_matches = dropped_matches.apply(find_winner, axis='columns')
dropped_matches.head()
# 将team_name字典中的团队名称替换为id
def replace_team_name_by_id(df):
df['Home Team Name'] = team_name[df['Home Team Name']]
df['Away Team Name'] = team_name[df['Away Team Name']]
return df
teamid_matches = dropped_matches.apply(replace_team_name_by_id, axis='columns')
teamid_matches.head()
# 删除不必要的列
teamid_matches = teamid_matches.drop(['Year', 'Home Team Goals', 'Away Team Goals'], 1)
teamid_matches.head()
X = teamid_matches[['Home Team Name', 'Away Team Name', 'Home Team Championship','Away Team Championship']]
X = np.array(X).astype('float64')
# 附加数据:只需将“主队名称”替换为“客场球队名称”,将“主队冠军”替换为“客场球队冠军”,然后替换结果
_X = X.copy()
_X[:,0] = X[:,1]
_X[:,1] = X[:,0]
_X[:,2] = X[:,3]
_X[:,3] = X[:,2]
y = dropped_matches['Winner']
y = np.array(y).astype('int')
y = np.reshape(y,(1,850))
y = y[0]
_y = y.copy()
for i in range(len(_y)):
if(_y[i]==1):
_y[i] = 2
elif(_y[i] ==2):
_y[i] = 1
X = np.concatenate((X,_X), axis= 0)
y = np.concatenate((y,_y))
print(X)
print(y)
# 打乱数据,然后拆分数据集为训练集和测试集
X,y = shuffle(X,y)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
# 用SVM支持向量机模型进行训练
svm_model = SVC(kernel='rbf', class_weight='balanced', probability=True)
svm_model.fit(X, y)
print("Predicting on the test set")
y_pred = svm_model.predict(X_test)
print(svm_model.score(X_test,y_test))
print(classification_report(y_test, y_pred))
print(confusion_matrix(y_test, y_pred, labels=range(3)))
# 构建决策树模型
from sklearn.tree import DecisionTreeClassifier
tree_model = DecisionTreeClassifier()
tree_model.fit(X, y)
print("Predicting on the test set")
y_pred = tree_model.predict(X_test)
print(tree_model.score(X_test,y_test))
print(classification_report(y_test, y_pred))
print(confusion_matrix(y_test, y_pred))
# 定义一个预测函数,需要传递两个球队名称,输出两个获胜的概率
def prediction(team1, team2):
id1 = team_name[team1]
id2 = team_name[team2]
championship1 = championships.get(team1) if championships.get(team1) != None else 0
championship2 = championships.get(team2) if championships.get(team2) != None else 0
x = np.array([id1, id2, championship1, championship2]).astype('float64')
x = np.reshape(x, (1,-1))
_y = svm_model.predict_proba(x)[0]
text = ('Chance for '+team1+' to win '+team2+' is {}
Chance for '+team2+' to win '+team1+' is {}
Chance for '+team1+' and '+team2+' draw is {}').format(_y[1]*100,_y[2]*100,_y[0]*100)
return _y[0], text
# 预测英格兰对法国的比赛
prob, text = prediction('England', 'France')
print(text)
# 预测阿根廷对克罗地亚的比赛
prob, text = prediction('Argentina', 'Croatia')
print(text)
# 预测法国对摩洛哥的比赛
prob, text = prediction('France', 'Morocco')
print(text)
# 预测克罗地亚对摩洛哥的比赛
prob, text = prediction('Croatia', 'Morocco')
print(text)
# 预测阿根廷对法国的比赛
prob, text = prediction('Argentina','France')
print(text)