网易首页 > 网易号 > 正文 申请入驻

撸啊撸~开局10分钟机器学习就能预测比赛的胜负!

0
分享至

From:数据科学家联盟

  • 0 前言

  • 1 任务介绍

  • 2 导入工具包

  • 3 读入数据

  • 4 数据概览

  • 5 特征处理

  • 6 特征相关性

  • 7 数据集准备

  • 8 模型训练和测试

  • 9 交叉验证

  • 10 模型参数

  • 11 可视化特征权重

  • 12 总结

0 前言

当前,2020英雄联盟全球总决赛(S10)正在如火如荼地进行,相信没有哪个英雄联盟玩家会错过这场受众超广、影响力超大的国际电竞赛事了。

值得一提的是,自9月25日开启的入围赛,本次大赛开创了自S赛设立入围赛阶段赛事以来,首次“无一队全败,无一队全胜”的惊人纪录。这一纪录也将预示着2020英雄联盟全球总决赛将有可能成为竞争最为激烈、也最具看点的一届赛事。

而每场比赛,每位观众最关注的莫过于最后的胜负了,但其实,在开局10分钟内,我们就能预测到一场比赛的胜负,今天,我们调取了9879场从钻一到大师段位的单双排位对局数据,手把手教你如何在开局10分钟就能预测比赛的胜负!

1 任务介绍

英雄联盟(League of Legends,LoL)是一个多人在线竞技游戏,由拳头游戏(Riot Games)公司出品。

在游戏中,每位玩家控制一位有独特技能的英雄,红蓝两支队伍各有五位玩家进行对战,目标是摧毁对方的基地水晶。水晶有多座防御塔保护,通常需要先摧毁一些防御塔再摧毁水晶。

玩家所控制的英雄起初非常弱,需要不断击杀小兵、野怪和对方英雄来获得金币、经验。经验可以提升英雄等级和技能等级,金币可以用来购买装备提升攻击、防御等属性。

对战过程中一般没有己方单位在附近的地点是没有视野的,即无法看到对面单位,双方可以通过使用守卫来监视某个地点,洞察对面走向、制定战术。

本数据集来自Kaggle,包含了9879场钻一到大师段位的单双排对局,对局双方几乎是同一水平。每条数据是前10分钟的对局情况,每支队伍有19个特征,红蓝双方共38个特征。这些特征包括英雄击杀、死亡,金钱、经验、等级情况等等。

一局游戏一般会持续30至40分钟,但是实际前10分钟的局面很大程度上影响了之后胜负的走向。作为最成功的电子竞技游戏之一,对局数据、选手数据的量化与研究具有重要意义,可以启发游戏将来的发展和改进。

本任务是希望构建机器学习模型根据已有的对局前10分钟特征信息,预测最后获胜方是蓝色方还是红色方。

2 导入工具包

pandas是数据分析和处理常用的工具包,非常适合处理行列表格数据。

numpy是数学运算工具包,支持高效的矩阵、向量运算。

matplotlibseaborn是作图常用工具包,其中seaborn是基于matplotlib的高级封装,使用一般更简便。

sklearn是机器学习常用工具包,包括了一些已经实现好的简单模型和一些常用数据处理方法、评价指标等函数。

import pandas as pd # 数据处理
import numpy as np # 数学运算
import matplotlib.pyplot as plt # 作图
import seaborn as sns # 作图
from sklearn.linear_model import LogisticRegression # 逻辑回归
from sklearn.preprocessing import MinMaxScaler # 归一化函数
from sklearn.model_selection import train_test_split, cross_validate # 划分数据集函数
from sklearn.metrics import accuracy_score # 准确率函数
RANDOM_SEED = 2020 # 固定随机种子
3 读入数据

假设数据文件放在./data/目录下,标准的csv文件可以用pandas里的read_csv()函数直接读入。文件共有40列,38个特征(红蓝方各19),1个标签列(blueWins),和一个对局标号(gameId)。对局标号不是标签也不是特征,可以舍去。

csv_data = './data/high_diamond_ranked_10min.csv' # 数据路径
data_df = pd.read_csv(csv_data, sep=',') # 读入csv文件为pandas的DataFrame
data_df = data_df.drop(columns='gameId') # 舍去对局标号列
4 数据概览

对于一个机器学习问题,在拿到任务和数据后,首先需要观察数据的情况,比如我们可以通过.iloc[0]取出数据的第一行并输出。不难看出每个特征都存成了float64浮点数,该对局蓝色方开局10分钟有小优势。同时也可以发现有些特征列是重复冗余的,比如blueGoldDiff表示蓝色队金币优势,redGoldDiff表示红色方金币优势,这两个特征是完全对称的互为相反数。

blueCSPerMin是蓝色方每分钟击杀小兵数,它乘10就是10分钟所有小兵击杀数blueTotalMinionsKilled。在之后的特征处理过程中可以考虑去除这些冗余特征。

另外,pandas有非常方便的describe()函数,可以直接通过DataFrame进行调用,可以展示每一列数据的一些统计信息,对数据分布情况有大致了解,比如blueKills蓝色方击杀英雄数在前十分钟的平均数是6.14、方差为2.93,中位数是6,百分之五十以上的对局中该特征在4-8之间,等等。

print(data_df.iloc[0]) # 输出第一行数据
data_df.describe() # 每列特征的简单统计信息

5 特征处理

传统的机器学习模型大部分都是基于特征的,因此特征工程是机器学习中非常重要的一步。有时构造一个好的特征比改进一个模型带来的提升更大。这里简单展示一些特征处理的例子。

首先,上面提到,特征列中有些特征信息是完全冗余的,会给模型带来不必要的计算量,可以去除。其次,相比于红蓝双方击杀、助攻的绝对值,可能双方击杀英雄的差值更能体现出当前对战的局势。

因此,我们可以构造红蓝双方对应特征的差值。数据文件中已有的差值是金币差GoldDiff和经验差ExperienceDiff,实际上每个对应特征都可以构造这样的差值特征。

drop_features = ['blueGoldDiff', 'redGoldDiff',
'blueExperienceDiff', 'redExperienceDiff',
'blueCSPerMin', 'redCSPerMin',
'blueGoldPerMin', 'redGoldPerMin'] # 需要舍去的特征列
df = data_df.drop(columns=drop_features) # 舍去特征列
info_names = [c[3:] for c in df.columns if c.startswith('red')] # 取出要作差值的特征名字(除去red前缀)
for info in info_names: # 对于每个特征名字
df['br' + info] = df['blue' + info] - df['red' + info] # 构造一个新的特征,由蓝色特征减去红色特征,前缀为br

6 特征相关性

为了了解每个特征的重要性或者特征之间的关联性,可以求两两特征或特征和标签之间的相关性。

本样例以红蓝双方的差值特征为例,求了两两特征之间的pearson相关系数,并可视化为热力图矩阵。相关系数的值在-1到1之间,越接近1表示正相关性越强,越接近-1表示负相关性越强。

在相关性矩阵中,不难看出对角都是1,是因为一个特征和自身的相关性自然是最强正相关。矩阵是对称的,因为特征A和特征B的相关性等价于特征B与特征A的相关性。从第一行(或列)可以看出哪些特征和标签blueWins相关。最强正相关性的特征是队伍金币差brTotalGold,和标签的正相关性表示该特征值越大,标签值一般情况下也越大(越可能为1),这很自然因为蓝色方前十分钟的金币优势越大,最终获胜的可能性也越大。

特征和特征之间的相关性也可以从矩阵中看出来,比如右下角蓝色的一块包括队伍金币差brTotalGold、队伍平均等级差brAvgLevel和队伍总经验差brTotalExperience三个特征,另外加上击杀英雄差brKills四个特征,它们两两特征之间的正相关性都非常高,这也很好理解,因为击杀英雄多了,金币和经验就多了,等级也高了,获胜的概率也高了,因此和标签的正相关性也都较高。但是一般我们不希望高相关性的特征太多,因为希望不同特征能覆盖不同的信息,而不是重复冗余的信息,例如之前去除的是完全冗余的相关性为1的特征。

plt.figure(figsize=(16, 12)) # 设置图像大小
# 获得相关性矩阵,pandas的DataFrame有直接的函数
corr_matrix = df[[c for c in df.columns if c == 'blueWins' or c.startswith('br')]].corr()
cg = sns.heatmap(corr_matrix, cmap='YlGnBu', annot=True, fmt='.2f', vmin=0); # 用seaborn作热力图
7 数据集准备

构建机器学习模型前要构建训练和测试的数据集。在本例中首先需要分开标签和特征,标签是不能作为模型的输入特征的,就好比作业和试卷答案不能在做题和考试前就告诉学生。另外比较重要的一点是本任务中特征值的范围差距很大,有些特征大于一万,有些特征一般小于10,对于有些模型包括神经网络模型,可能会不利于参数学习,增加训练难度。

因此通常会将特征值标准化到0-1之间,比如本例中我们使用sklearn提供的MinMaxScaler,将所有样本的某一列特征,最大值映射到1,最小值映射到0。

测试一个模型在一个任务上的效果至少需要训练集和测试集,训练集用来训练模型的参数,好比学生做作业获得知识,测试集用来测试模型效果,好比期末考试考察学生学习情况。

测试集的样本不应该出现在训练集中,否则会造成模型效果估计偏高,好比考试时出的题如果是作业题中出现过的,会造成考试分数不能准确衡量学生的学习情况,估计值偏高。

划分训练集和测试集有多种方法,下面首先介绍的是随机取一部分如20%作测试集,剩下作训练集。sklearn提供了相关工具函数train_test_split。sklearn的输入输出一般为numpy的array矩阵,需要先将pandas的DataFrame取出为numpy的array矩阵。

all_y = df['blueWins'].values # 所有原始特征值,pandas的DataFrame.values取出为numpy的array矩阵
all_x = df[df.columns[1:]].values # 所有标签数据
scaler = MinMaxScaler().fit(all_x) # 需要对特征作归一化,sklearn提供了相关工具
all_x = scaler.transform(all_x) # 将特征归一化到01
# 划分训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(all_x, all_y, test_size=0.2, random_state=RANDOM_SEED)
all_y.shape, all_x.shape, x_train.shape, x_test.shape, y_train.shape, y_test.shape # 输出数据行列信息

((9879,), (9879, 45), (7903, 45), (1976, 45), (7903,), (1976,))
8 模型训练和测试

本例以sklearn中的逻辑回归LogisticRegression为例展示模型的训练和测试过程,它是个线性分类器。sklearn中还有很多其他分类器如KNN、决策树、SVM等等。

调用非常简单,给定一些超参数如最大迭代轮次等初始化一个LogisticRegression()类之后,可以通过fit()函数进行训练,predict()函数可以用来对样本进行预测输出预测值。

本例采用准确率进行评价sklearn中有accuracy_score()函数帮助计算准确率。如果效果不好,可以尝试调整模型的超参数,如最大训练轮次、学习速率、正则化项权重等。

LR = LogisticRegression(random_state=RANDOM_SEED, verbose=1, max_iter=1000) # 初始化逻辑回归模型
LR.fit(x_train, y_train) # 在训练集上训练
p_test = LR.predict(x_test) # 在测试集上预测,获得预测值
print(p_test) # 输出预测值
test_acc = accuracy_score(p_test, y_test) # 将测试预测值与测试集标签对比获得准确率
print('accuracy: {:.4}'.format(test_acc)) # 输出准确率

[0 1 0 ... 0 1 1]
accuracy: 0.7328

[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done 1 out of 1 | elapsed: 0.2s finished
9 交叉验证

在数据量不是很大的情况下,测试集可能也不够大,不能准确估计所得到的模型在未见样本上的效果,并且单次训练测试可能有偏差,一般需要重复多次训练测试取平均值。

一种常用的重复实验的方式是交叉验证,它将整个数据集划分为K份,每次取其中一份作为测试集,其他K-1份作为训练集,取K次测试结果的平均作为最终模型的准确率。

sklearn同样提供了非常方便的交叉验证的接口cross_validate,输入定义好的模型,所有训练数据以及折数K,可以得到每折训练测试的结果。例如下面代码中cv=5表示5折交叉验证。

LR = LogisticRegression(random_state=RANDOM_SEED, verbose=0, max_iter=1000) # 定义逻辑回归模型
scores = cross_validate(LR, all_x, all_y, cv=5, scoring=('accuracy'), return_train_score=True) # 5折交叉验证
print(scores) # 交叉验证的结果,是个python的dict,存有训练时间fit_time、测试时间score_time,测试准确率test_score,训练准确率train_score
print('average accuracy: {:.4f}'.format(np.mean(scores['test_score']))) # 输出多折的测试准确率均值

{'fit_time': array([0.15559244, 0.16526341, 0.18318272, 0.16132855, 0.1458261 ]), 'score_time': array([0.00039506, 0.0004127 , 0.00040436, 0.00039434, 0.00039506]), 'test_score': array([0.7388664 , 0.72975709, 0.73279352, 0.7388664 , 0.72607595]), 'train_score': array([0.73326585, 0.73351892, 0.73415159, 0.73073516, 0.73380567])}
average accuracy: 0.7333
10 模型参数

大部分模型都有一些参数,会根据训练集训练出合适的值。在sklearn中,训练完成后可以输出模型参数进行查看。例如在逻辑回归模型中比较重要的参数是每个特征的权重coef_

在本例中,对应特征的权重绝对值越大,表示对分类预测的贡献越大。正值表示该特征值越大越偏向预测蓝色方胜利,相反的负值表示偏向预测红色方胜利。

LR.fit(x_train, y_train) # 训练模型
print(LR.classes_.shape, LR.classes_) # 类别个数
print(LR.n_iter_.shape, LR.n_iter_) # 训练执行轮次
print(LR.coef_.shape, LR.coef_) # 特征权重
print(LR.intercept_.shape, LR.intercept_) # 分类截距
11 可视化特征权重

研究模型的参数可以帮助我们理解模型分类预测的依据,对结果作解释。例如我们将每个特征对应的权重用柱状图表示出来,见下图。

不难看到,和之前的分析结果相一致,最重要的特征包括蓝色方队伍金币blueTotalGold、红色方队伍金币redTotalGold、队伍金币差brTotalGold、队伍经验差brTotalExperience等,蓝色队伍金币经验领先越大,模型越可能预测蓝色方胜利。

plt.figure(figsize=(8,15))
sns.barplot(x=LR.coef_[0], y=df.columns[1:])


12 总结

一个完整的机器学习任务包括:确定任务、数据分析、特征工程、数据集划分、模型设计、模型训练和效果测试、结果分析和调优等多个阶段,本案例以英雄联盟游戏胜负预测任务为例,给出了每个阶段的一些简单例子,帮助大家入门机器学习,希望大家有所收获!

我的朋友圈更精彩

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
世界杯突发悲剧!多家外媒:25岁南非国脚上吊自杀,本届出场3次

世界杯突发悲剧!多家外媒:25岁南非国脚上吊自杀,本届出场3次

我爱英超
2026-07-11 20:12:21
1959年宋希濂被特赦,举目无亲时,陈赓一声“宋大头”,让他崩溃

1959年宋希濂被特赦,举目无亲时,陈赓一声“宋大头”,让他崩溃

阿器谈史
2026-07-11 14:05:41
彭德怀担任国防部长时,副部长全是大将、上将,唯廖汉生是中将

彭德怀担任国防部长时,副部长全是大将、上将,唯廖汉生是中将

大运河时空
2026-07-11 08:50:03
下周入伏!接下来的40天别忘了煮这些吃,祛湿强免疫,一年病少来!

下周入伏!接下来的40天别忘了煮这些吃,祛湿强免疫,一年病少来!

白宸侃片
2026-07-11 00:26:49
好突然!25岁足球新星刚踢完世界杯离世,前一天还晒女友合照,当地媒体曝疑似轻生

好突然!25岁足球新星刚踢完世界杯离世,前一天还晒女友合照,当地媒体曝疑似轻生

华人生活网
2026-07-12 03:04:45
俄罗斯急了?中朝韩铁路一旦贯通,日本或将沦为东亚孤家寡人

俄罗斯急了?中朝韩铁路一旦贯通,日本或将沦为东亚孤家寡人

最新声音
2026-07-11 20:59:02
回归家庭!乔治娜Ins晒与C罗一起度假的合影:Papis

回归家庭!乔治娜Ins晒与C罗一起度假的合影:Papis

老吴教育课堂
2026-07-12 03:19:22
俄工厂未经授权组装宝马,145辆已卖出,宝马警告安全风险

俄工厂未经授权组装宝马,145辆已卖出,宝马警告安全风险

桂系007
2026-07-11 23:58:16
抽象!网友用一根葱模仿哈兰德,哈兰德回复了一个表情包

抽象!网友用一根葱模仿哈兰德,哈兰德回复了一个表情包

懂球帝
2026-07-11 14:25:17
南非25岁足球国脚上吊自杀,世界杯出战3次,生前转发与女友合照

南非25岁足球国脚上吊自杀,世界杯出战3次,生前转发与女友合照

译言
2026-07-12 09:05:18
广东知名女主持人坚守27年,55岁仍貌美如花

广东知名女主持人坚守27年,55岁仍貌美如花

圆梦的小老头
2026-07-12 05:08:54
研究发现:菊花茶可以在一天内溶解血栓、扩张血管,是真的吗?

研究发现:菊花茶可以在一天内溶解血栓、扩张血管,是真的吗?

芹姐说生活
2026-07-11 23:15:46
伊朗疑遭阿拉伯联军轰炸,以总理:攻击伊朗就像切除癌症

伊朗疑遭阿拉伯联军轰炸,以总理:攻击伊朗就像切除癌症

移光幻影
2026-07-11 16:56:30
空调开26度亏大了!工程师:调这个数,电费少一半

空调开26度亏大了!工程师:调这个数,电费少一半

小柱解说游戏
2026-07-09 08:24:27
又一大学宣布取消英语课!评论区吵翻了……

又一大学宣布取消英语课!评论区吵翻了……

教材帮
2026-07-11 20:08:17
勇士正式签约!老詹,没戏了…

勇士正式签约!老詹,没戏了…

左右为篮
2026-07-12 00:06:17
里程碑之战!阿根廷vs瑞士成本届世界杯第100场比赛

里程碑之战!阿根廷vs瑞士成本届世界杯第100场比赛

懂球帝
2026-07-12 09:29:14
英国能单独对抗俄罗斯吗?俄罗斯:全世界能赢我的国家,顶多两个

英国能单独对抗俄罗斯吗?俄罗斯:全世界能赢我的国家,顶多两个

西府赵王爷
2025-03-07 13:12:22
政坛地震!检察日报评论要让泰山景区领导睡不着觉了!

政坛地震!检察日报评论要让泰山景区领导睡不着觉了!

娱乐小可爱蛙
2026-07-11 20:58:18
特斯拉中国全新 Model Y 来了!这价格太猛啦

特斯拉中国全新 Model Y 来了!这价格太猛啦

XCiOS俱乐部
2026-07-11 10:27:00
2026-07-12 10:56:49
Ai学习的老章 incentive-icons
Ai学习的老章
Ai学习的老章
3467文章数 11172关注度
往期回顾 全部

科技要闻

Meta又闯祸了,新AI图像功能被喷到下线

头条要闻

游客在深圳梧桐山突发不适离世 气象部门发布安全提示

头条要闻

游客在深圳梧桐山突发不适离世 气象部门发布安全提示

体育要闻

贝林厄姆送走哈兰德:英格兰天命之子!

娱乐要闻

迪丽热巴估计都无语了 亲自下场辟

财经要闻

美联储和市场将走向何方?

汽车要闻

预售权益价11.78万起 五菱星光L将于7月16日上市

态度原创

数码
亲子
本地
公开课
军事航空

数码要闻

显卡价格普涨超20%!只有AMD RX 9070 GRE在降价

亲子要闻

睡得好和睡不好,孩子的区别有多大!

本地新闻

重庆人有自己的避暑桃花源 | 夏天就去「酉」风的地方!

公开课

李玫瑾:为什么性格比能力更重要?

军事要闻

伊朗宣布关闭霍尔木兹海峡:直至美国停止干涉该地区

无障碍浏览 进入关怀版