【机器学习】 - 作业1: 基于决策树的英雄联盟游戏胜负预测

课程链接: 清华大学驭风计划

代码仓库:Victor94-king/MachineLearning: MachineLearning basic introduction (github.com)


驭风计划是由清华大学老师教授的,其分为四门课,包括: 机器学习(张敏教授) , 深度学习(胡晓林教授), 计算机语言(刘知远教授) 以及数据结构与算法(邓俊辉教授)。本人是综合成绩第一名,除了数据结构与算法其他单科均为第一名。代码和报告均为本人自己实现,由于篇幅限制,只展示任务布置以及关键代码,如果需要报告或者代码可以私聊博主



机器学习部分授课老师为张敏教授,主要主要通过介绍决策树,线性回归,贝叶斯模型,SVM算法,K近邻算法,Kmeans算法以及集成学习算法等入门机器学习。

有任何疑问或者问题,也欢迎私信博主,大家可以相互讨论交流哟~~



任务介绍

本次以英雄联盟对局胜负预测任务为基础,要求实现决策树算法相关细节,加深对算法的理解,并了解做机器学习任务的大致流程。


英雄联盟(League of Legends,LoL)是一个多人在线竞技游戏,由拳头游戏(Riot Games)公司出品。在游戏中,每位玩家控制一位有独特技能的英雄,红蓝两支队伍各有五位玩家进行对战,目标是摧毁对方的基地水晶。水晶有多座防御塔保护,通常需要先摧毁一些防御塔再摧毁水晶。玩家所控制的英雄起初非常弱,需要不断击杀小兵、野怪和对方英雄来获得金币、经验。经验可以提升英雄等级和技能等级,金币可以用来购买装备提升攻击、防御等属性。对战过程中一般没有己方单位在附近的地点是没有视野的,即无法看到对面单位,双方可以通过使用守卫来监视某个地点,洞察对面走向、制定战术。

本数据集来自Kaggle,包含了9879场钻一到大师段位的单双排对局,对局双方几乎是同一水平。每条数据是前10分钟的对局情况,每支队伍有19个特征,红蓝双方共38个特征。这些特征包括英雄击杀、死亡,金钱、经验、等级情况等等。一局游戏一般会持续30至40分钟,但是实际前10分钟的局面很大程度上影响了之后胜负的走向。作为最成功的电子竞技游戏之一,对局数据、选手数据的量化与研究具有重要意义,可以启发游戏将来的发展和改进。



本任务是希望同学们依据注释的要求,对代码中空缺部分进行填写,完成决策树模型的详细实现,根据已有的对局前10分钟特征信息,预测最后获胜方是蓝色方还是红色方,了解执行一个机器学习任务的大致流程,并提交代码和实验报告。第一次作业也是一个机器学习小实验的例子,之后的作业可能不再提供预处理等流程代码,由同学们自己设计实验完成代码编写。



报告

核心代码

决策树的实现

def expand_node(self, features , lable , depth):
    #情况1: 无需分裂 or 到达阈值直接返回样本最多的值
    majority_feature = self.count_lable(lable)
    #print(majority_feature.index[0])
    if len(majority_feature) == 1: #样本标签唯一
        return lable[0]
    if len(features)  <= self.min_samples_split:  # 样本个数小于阈值
        return majority_feature.index[0] 
    if depth >= self.max_depth: #深度超过max
        return majority_feature.index[0]
    if np.unique(features).shape[0] == features.shape[0] and len(majority_feature) != 1: 
        print('所有样本的属性值一样但对应的标签不一致') #此处需要考虑噪声和未考虑全的特征
        print(depth)
    # 返回最大信息熵的特征的index,用于分裂
    feature_index = self.gain(features, lable)  

    #找到特征的属性值可能选项
    unique_values = np.unique(features[:,feature_index])

    #核心递归:构建一个嵌套字典结构{特征index:{value = {submytree }}}},对不同的value进行递归遍历
    myTree = { feature_index:{} }  # tree 
    for value in unique_values:
        #新建一个splitDataSet 函数:传入特征矩阵, 最优的节点,寻找的值,标签 
        sublabels , subfeatures  = self.splitDataSet(features , feature_index, value , lable)
        #subfeatures = np.delete(features ,feature_index , axis = 1) 
        myTree[feature_index][value] = self.expand_node(subfeatures , sublabels, depth = depth + 1)
    return myTree

### 总结

步骤:

1. 读取数据,观察并分析数据。看有无特征是否有线性关系,有无缺失的数据,缺失的数据可以进行填充/取均值等方式
2. 数据处理。由于决策树主要还是解决一些离散数据,所以需要利用qcut/cut函数进行离散化,将数据集映射到比较选值范围比较少的区间内,便于生成树,也避免了后期树优先选择范围较多的节点
3. 准备数据集(training/validation/testing):采用随机的方式,需要保证几个数据集没有重合的部分
4. 决策树类的构建:

   一)构造函数:可以输入一些决策树的属性,eg:最大深度,最大阈值,最小样本数量,混杂度,输出结果的范围,特征名等

   二)定义树的训练函数fit(feature , lable):从跟节点开始生长,返回值是一个多层的树结构(嵌套字典)并记录下来

   *三)定义根的生长函数expand_node(feature , lable , depth):这个函数是一个核心部分,递归。

   四) 定义最优节点取值index函数gain(feature,lable)

   五) 定义splitDataSet(feature,lable,feature_index,value)

   六) 定义辅助函数:包括计算混杂度函数,以及由于传入的lable是np.array没有value_counts()方法可以自己定义

   七) 定义预测函数prdict(feature):单独遍历feature里每一行(样本)的特征,返回的所有值作为行向量输出

   *八) 定义预测单数据的函数traverse_node(node,single_sample_feature)
5. 训练模型 -> 验证集上调整超参数/后剪枝叶 -> 得到测试集正确率

***) 难点:

1. (7932,)与(7932,1)是不一样的前者是行向量后者为列向量,但可以通过reshape后再进行数组拼接
2. 利用qcut函数将其等分,discrete_df[c].rank(method="first")是为了去重,qcut函数中不允许重复值切分。之后可以使用cut函数
3. 对于一些超参数的调整:由于决策树的特殊原因,始终可以让训练集上的正确率不断增加,但需要考虑过拟合的风险,在max_depth设成10层的时候,训练集的正确率高达80%但是测试集却下降到了60%

你可能感兴趣的:(学堂在线,机器学习,决策树,游戏)