实验目的

根据对局前10分钟信息预测蓝方结局胜负。

方法

基于决策树模型,首先用训练集数据进行预处理,合理设计决策树结构,最后用测试机检测准确率。数据来源

过程

一,导入工具包

pandas是数据分析和处理常用的工具包,非常适合处理行列表格数据。numpy是数学运算工具包,支持高效的矩阵、向量运算。sklearn是机器学习常用工具包,包括了一些已经实现好的简单模型和一些常用数据处理方法、评价指标等函数。
由于我python仅有入门级别水平,这一过程涉及到许多我不曾了解的工具包。经过学习,个人感觉用处最大的是Counter与train_test_split。

Counter

Counter可起到计数器的作用,可统计传入参数(已使可行的有list和numpy)的各元素数量,在统计分析方面作用很大。

from collections import Counter
color = ['red','bule','white','red','bule']
c = Counter(color)
print(c)

统计过后,Counter也可以进行许多便捷操作,在本次实验中用到的是most_common,该函数可求出出现次数最多的k个元素

    def majorCnt(self, lable):Cnt = Counter(lable)return Cnt.most_common(1)[0][0]

train_test_split

X_train,X_test, y_train, y_test =sklearn.model_selection.train_test_split(train_data,train_target,test_size=0.4, random_state=0,stratify=y_train)
  • train_data:所要划分的样本特征集*
  • train_target:所要划分的样本结果*
  • test_size:样本占比,如果是整数的话就是样本的数量*
  • random_state:是随机数的种子。*
  • 随机数种子:其实就是该组随机数的编号,在需要重复试验的时候,保证得到一组一样的随机数。比如你每次都填1,其他参数一样的情况下你得到的随机数组是一样的。但填0或不填,每次都会不一样。*

stratify是为了保持split前类的分布。比如有100个数据,80个属于A类,20个属于B类。如果train_test_split(… test_size=0.25, stratify = y_all), 那么split之后数据如下:
training: 75个数据,其中60个属于A类,15个属于B类。
testing: 25个数据,其中20个属于A类,5个属于B类。

用了stratify参数,training集和testing集的类的比例是 A:B= 4:1,等同于split前的比例(80:20)。通常在这种类分布不平衡的情况下会用到stratify。

将stratify=X就是按照X中的比例分配

将stratify=y就是按照y中的比例分配

二,读入数据

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

drop([ ],axis=0,inplace=True)

drop([]),默认情况下删除某一行;
如果要删除某列,需要axis=1;
参数inplace 默认情况下为False,表示保持原来的数据不变,True 则表示在原来的数据上改变。

import pandas as pdimport numpy as npdata=pd.DataFrame(np.arange(20).reshape((5,4)),columns=list('ABCD'),index=['a','b','c','d','e'])
print(data)
print('*'*40)
print(data.drop(['a'])) #删除a 行,默认inplace=False,
print('*'*40)
print(data)#  data 没有变化
print('*'*40)
print(data.drop(['A'],axis=1))#删除列
print('*'*40)
print(data.drop(['A'],axis=1,inplace=True)) #在本来的data 上删除
print('*'*40)
print(data)data 发生变化

三,数据概览

对于一个机器学习问题,在拿到任务和数据后,首先需要观察数据的情况,比如我们可以通过.iloc[0]取出数据的第一行并输出。不难看出每个特征都存成了float64浮点数,该对局蓝色方开局10分钟有小优势。同时也可以发现有些特征列是重复冗余的,比如blueGoldDiff表示蓝色队金币优势,redGoldDiff表示红色方金币优势,这两个特征是完全对称的互为相反数。blueCSPerMin是蓝色方每分钟击杀小兵数,它乘10就是10分钟所有小兵击杀数blueTotalMinionsKilled。在之后的特征处理过程中可以考虑去除这些冗余特征。
另外,pandas有非常方便的describe()函数,可以直接通过DataFrame进行调用,可以展示每一列数据的一些统计信息,对数据分布情况有大致了解,比如blueKills蓝色方击杀英雄数在前十分钟的平均数是6.14、方差为2.93,中位数是6,百分之五十以上的对局中该特征在4-8之间,等等。

四,增删特征

传统的机器学习模型大部分都是基于特征的,因此特征工程是机器学习中非常重要的一步。有时构造一个好的特征比改进一个模型带来的提升更大。这里简单展示一些特征处理的例子。首先,上面提到,特征列中有些特征信息是完全冗余的,会给模型带来不必要的计算量,可以去除。其次,相比于红蓝双方击杀、助攻的绝对值,可能双方击杀英雄的差值更能体现出当前对战的局势。因此,我们可以构造红蓝双方对应特征的差值。数据文件中已有的差值是金币差GoldDiff和经验差ExperienceDiff,实际上每个对应特征都可以构造这样的差值特征。

五,特征离散化

决策树ID3算法一般是基于离散特征的,本例中存在很多连续的数值特征,例如队伍金币。直接应用该算法每个值当作一个该特征的一个取值可能造成严重的过拟合,因此需要对特征进行离散化,即将一定范围内的值映射成一个值,例如对用户年龄特征,将0-10映射到0,11-18映射到1,19-25映射到2,25-30映射到3,等等类似,然后在决策树构建时使用映射后的值计算信息增益。
此处涉及到分类多少的问题,需要平衡提高准确率与防止过拟合之间的关系

六,数据集准备

构建机器学习模型前要构建训练和测试的数据集。在本例中首先需要分开标签和特征,标签是不能作为模型的输入特征的,就好比作业和试卷答案不能在做题和考试前就告诉学生。测试一个模型在一个任务上的效果至少需要训练集和测试集,训练集用来训练模型的参数,好比学生做作业获得知识,测试集用来测试模型效果,好比期末考试考察学生学习情况。测试集的样本不应该出现在训练集中,否则会造成模型效果估计偏高,好比考试时出的题如果是作业题中出现过的,会造成考试分数不能准确衡量学生的学习情况,估计值偏高。划分训练集和测试集有多种方法,下面首先介绍的是随机取一部分如20%作测试集,剩下作训练集。sklearn提供了相关工具函数train_test_split。sklearn的输入输出一般为numpy的array矩阵,需要先将pandas的DataFrame取出为numpy的array矩阵。

七,实现决策树

本部分为本次作业主要完成内容,期间遇到过信息增益传值错误,递归结构混乱,数据集特定分支确实等问题。本部分代码写法主要参考b站视频BV1KL4y1B7VB与github开源资源。

结果

经过调整可调的超参数,在不改变已给代码的基本上,预测准确率可达0.71,并在改变随机seed后平均准确率维持在0.7左右

思考

1.在对数据进行离散化时,将数据直接分为两类的方法会使得最后的准确率最高,而更为精细的分类反而会使准确率降低,过拟合问题比我想象中要更加容易出现
2.在预测时存在测试集中出现训练集中没有的特征分类,该问题暂未实现较好解决,在代码中只是简单地用模型已知的一个特征直接覆盖该未知特征分类,对预测准确率毫无疑问造成了影响,后续需想办法改进
3.在离散化采用较多的分类时,为平衡其带来的信息增益,我尝试使用GainRatio来代替信息增益,结果使得预测准确率由0.6775上升至0.6817,但仍不及离散化时采用减少分类的模型

结尾附代码

from collections import Counter
import pandas as pd  # 数据处理
import numpy as np  # 数学运算
from sklearn.model_selection import train_test_split, cross_validate  # 划分数据集函数
from sklearn.metrics import accuracy_score  # 准确率函数
RANDOM_SEED = 2020  # 固定随机种子
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')  # 舍去对局标号列
print(data_df.iloc[0])  # 输出第一行数据
data_df.describe()  # 每列特征的简单统计信息
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
# 其中FirstBlood为首次击杀最多有一只队伍能获得,brFirstBlood=1为蓝,0为没有产生,-1为红
df = df.drop(columns=['blueFirstBlood', 'redFirstBlood'])  # 原有的FirstBlood可删除discrete_df = df.copy()  # 先复制一份数据
for c in df.columns[1:]:  # 遍历每一列特征,跳过标签列if c == 'blue' + 'EliteMonsters' or c == 'red' + 'EliteMonsters' or c == 'br' + 'EliteMonsters':continueif c == 'blue' + 'Dragons' or c == 'red' + 'Dragons' or c == 'br' + 'Dragons':continueif c == 'blue' + 'Heralds' or c == 'red' + 'Heralds' or c == 'br' + 'Heralds':continueif c == 'blue' + 'TowersDestroyed' or c == 'red' + 'TowersDestroyed' or c == 'br' + 'TowersDestroyed':continueif c == 'brFirstBlood':continuediscrete_df[c] = pd.qcut(df[c].rank(method='first'), 2, labels=[1, 2])all_y = discrete_df['blueWins'].values  # 所有标签数据
feature_names = np.array(discrete_df.columns[1:])  # 所有特征的名称
all_x = discrete_df[feature_names].values  # 所有原始特征值,pandas的DataFrame.values取出为numpy的array矩阵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'''  # 输出数据行列信息class DecisionTree(object):def __init__(self, classes, features,max_depth=10, min_samples_split=10,impurity_t='entropy'):self.classes = classesself.features = featuresself.max_depth = max_depthself.min_samples_split = min_samples_splitself.impurity_t = impurity_tself.root = None  # 定义根节点,未训练时为空def impurity(self, feature):data_num = len(feature)cnt = Counter(feature)P_ele = np.array([cnt[lable] / data_num for lable in cnt])if self.impurity_t == 'gini':return 1-np.sum(np.power(P_ele, 2))if self.impurity_t == 'entropy':return -np.sum(np.multiply(P_ele, np.log2(P_ele)))def gain(self, feature, lable):numFeature = len(feature[0])sumimpurity = self.impurity(lable)bestGain = 0bestFeat = -1for i in range(numFeature):featlist = [example[i] for example in feature]uniquevals = set(featlist)subimpurity = 0for val in uniquevals:subfeature, sublable = self.dividefeat(feature, i, lable, val)a = self.impurity(sublable)subimpurity +=a* len(sublable) / len(feature)nowgain = (sumimpurity - subimpurity)if nowgain > bestGain:bestGain = nowgainbestFeat = ireturn bestFeatdef dividefeat(self, feature, tagfeature, lable, value):refeature = []relable = []features = feature.tolist()lables = lable.tolist()for i in range(len(feature)):feaVec = features[i]if feaVec[tagfeature] == value:subfeat = feaVec[:tagfeature]subfeat.extend(feaVec[tagfeature + 1:])refeature.append(subfeat)relable.append(lables[i])return np.array(refeature),np.array(relable)def majorCnt(self, lable):Cnt = Counter(lable)return Cnt.most_common(1)[0][0]def expand_node(self, feature, lable, depth):classcount = Counter(lable)if len(classcount) == 1:return lable[0]if len(feature[0]) <= self.min_samples_split:return self.majorCnt(lable)if depth > self.max_depth:return self.majorCnt(lable)bestFeat = self.gain(feature, lable)featValue = [example[bestFeat] for example in feature]uniqueval = set(featValue)subDT = {bestFeat:{}}for value in uniqueval:subfeature,sublable = self.dividefeat(feature, bestFeat, lable, value)subDT[bestFeat][value] = self.expand_node(subfeature, sublable, depth=depth + 1)return subDTdef fit(self, feature, label):assert len(self.features) == len(feature[0])  # 输入数据的特征数目应该和模型定义时的特征数目相self.root = self.expand_node(feature, label, depth=1)def traverse_node(self,node,feature):featname = [name for name in node.keys()][0]sb = [dsb for dsb in node[featname].keys()]if feature[featname] not in sb :feature[featname] = sb[0]if node[featname][feature[featname]] in self.classes :return node[featname][feature[featname]]return self.traverse_node(node[featname][feature[featname]],feature)def predict(self, feature):assert len(feature.shape) == 1 or len(feature.shape) == 2  # 只能是1维或2维if len(feature.shape) == 1:  # 如果是一个样本return self.traverse_node(self.root, feature)  # 从根节点开始路由return np.array([self.traverse_node(self.root, f) for f in feature])  # 如果是很多个样本DT = DecisionTree(classes=[0, 1], features=feature_names, max_depth=5, min_samples_split=10, impurity_t='gini')
DT.fit(x_train, y_train)  # 在训练集上训练
p_test = DT.predict(x_test)  # 在测试集上预测,获得预测值
print(p_test)  # 输出预测值
test_acc = accuracy_score(p_test, y_test)  # 将测试预测值与测试集标签对比获得准确率
print('accuracy: {:.4f}'.format(test_acc))  # 输出准确率

【实验一】基于决策树的英雄联盟游戏胜负预测实验报告相关推荐

  1. 【机器学习】实验1布置:基于决策树的英雄联盟游戏胜负预测

    ML_class 学堂在线<机器学习>实验课代码+报告(其中实验1和实验6有配套PPT),授课老师为张敏老师.课程链接:https://www.xuetangx.com/training/ ...

  2. 【ML】英雄联盟对局胜负预测任务

    本样例以英雄联盟对局胜负预测任务为基础,简单展示了机器学习任务的大致流程,为机器学习入门者提供参考. 任务介绍 英雄联盟(League of Legends,LoL)是一个多人在线竞技游戏,由拳头游戏 ...

  3. 基于NodeJS英雄联盟游戏游戏综合网站

    21世纪的今天,随着社会的不断发展与进步,人们对于信息科学化的认识,已由低层次向高层次发展,由原来的感性认识向理性认识提高,管理工作的重要性已逐渐被人们所认识,科学化的管理,使信息存储达到准确.快速. ...

  4. 【Matlab】基于决策树DT实现多分类预测(Excel可直接替换数据)

    [Matlab]基于决策树DT实现多分类预测(Excel可直接替换数据)) 1.算法简介 1.1 算法原理 1.2 算法优点 1.3 算法缺点 1.4 算法步骤 2.测试数据集 3.替换数据 4.混淆 ...

  5. 五子棋java设计引言_基于JAVA的五子棋游戏系统设计与实现报告.doc

    PAGE \* MERGEFORMAT PAGE \* MERGEFORMAT I 基于JAVA的五子棋游戏系统设计与实现 专 业 电子信息工程 学 生 董永杰 指导教师 曾玉 摘要 PAGE \* ...

  6. 基于matlab的传热学虚拟实验开发,基于MATLAB的传热学课程虚拟实验软件的开发

    215教育现代化·2018 年 12 月第 49 期 教育信息技术 基于 MATLAB 的传热学课程虚拟实验软件的开发 周永利,李友荣,石万元,张力元,杨晨,卞煜,王国强,李俊,包键 ( 重庆大学 低 ...

  7. 数字水印实验2 基于LSB和EMD的信息隐藏实验

    [实验名称]基于LSB和EMD的信息隐藏实验 [实验目的] 1.学习并掌握图像信息隐藏的基本原理和方法 2.学习并实现基于LSB的信息隐藏和提取算法 3.学习并实现基于EMD的信息隐藏和提取算法 [实 ...

  8. python 物理实验_基于Python和梯度下降算法的物理实验数据一元线性拟合方法

    基于 Python 和梯度下降算法的物理实验数据一元线性拟 合方法 关毅铬 ; 程敏熙 [期刊名称] < <物理通报> > [年 ( 卷 ), 期] 2019(000)010 ...

  9. 【机器学习】基于LightGBM的英雄联盟钻石排位数据集的训练、预测与简单可视化

    目录 一.学习知识点概要 二.学习内容 代码 1.导入库 2.数据载入与处理 3.绘制热力图/相关系数矩阵图 4.利用 LightBGM进行训练与测试 5.利用 LightGBM进行特征选择 6.模型 ...

最新文章

  1. digitalocean如何还原出厂设置
  2. Spring Cloud Gateway中异常处理
  3. Unit Testing in iOS
  4. Activiti源码 之 DataManager EntityManager
  5. vue解构赋值_前端开发es6知识 模块化、解构赋值、字符串模板
  6. python路径规划仿真实验_【python实战】批量获得路径规划——高德地图API
  7. C语言之数据结构基本概览(四十六)
  8. go语言构造函数的创建以及赋值使用
  9. bzoj 1861 treap
  10. 信捷电子凸轮使用_1.电子凸轮入门应用之基础知识介绍
  11. 【C语言】科学计数法——复习总结
  12. 牛逼!用文言文来编程,97 年 CMU 本科生火遍全网!
  13. html自定义属性jquery怎么拿到,jquery 获取自定义属性(attr和prop)的实现代码
  14. 计算机网络重置,怎么重置电脑网络连接
  15. 坦克大战Netty网络联机版项目笔记
  16. 一个简单的HTML网页
  17. C语言转义字符'\'
  18. (附源码)python电影院信息管理系统 毕业设计 021844
  19. Appscan测试工具简介
  20. 【服务器数据恢复】服务器硬盘黄灯的数据恢复案例分享

热门文章

  1. 未来IT工程师协会 会徽征集
  2. nlog官方帮助_NLog简介
  3. 早上9.10分左右上高架被拍了!
  4. Java、JSP B/S架构下的网络公告墙的设计与实现
  5. ThinkPad X1 Carbon安装win7.
  6. Elasticsearch 整合机器学习强化排序
  7. LearnOpenGL 光照—材质
  8. js关闭当前页面,chrome插件方式
  9. 【JAVA修行之路】--“斩杀”对象和类
  10. android 文件管理器 apk,华为手机文件管理器(com.huawei.hidisk) - 10.11.11.301 - 应用 - 酷安...