英雄联盟胜负预测--简易肯德基上校,2024年大数据开发知识体系总结

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新大数据全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注大数据)
img

正文

    '''
    c_impurity, _ = self.impurity(label)  # 不考虑特征时标签的混杂度

    # 记录特征的每种取值所对应的数组下标
    f_index = {}
    for idx, v in enumerate(feature):
        if v not in f_index:
            f_index[v] = []
        f_index[v].append(idx)

    # 计算根据该特征分裂后的不纯度,根据特征的每种值的数目加权和
    f_impurity = 0
    for v in f_index:
        # 根据该特征取值对应的数组下标 取出对应的标签列表 比如分支1有多少个正负例 分支2有...
        f_l = label[f_index[v]]
        f_impurity += self.impurity(f_l)[0] * len(f_l) / len(label)  # 循环结束得到各分支混杂度的期望

    gain = c_impurity - f_impurity  # 得到gain

    # 有些特征取值很多,天然不纯度高、信息增益高,模型会偏向于取值很多的特征比如日期,但很可能过拟合
    # 计算信息增益率可以缓解该问题
    splitInformation = self.impurity(feature)[0]  # 计算该特征在标签无关时的不纯度
    gainRatio = gain / splitInformation if splitInformation > 0 else gain  # 除数不为0时为信息增益率
    return gainRatio, f_index  # 返回信息增益率,以及每个特征取值的数组下标(方便以后使用)

def expand_node(self, feature, label, depth, skip_features=set()):
    '''
    递归函数分裂节点
    :param feature:二维numpy(n*m)数组,每行表示一个样本,n行,有m个特征
    :param label:一维numpy(n)数组,表示每个样本的分类标签
    :param depth:当前节点的深度
    :param skip_features:表示当前路径已经用到的特征
    在当前ID3算法离散特征的实现下,一条路径上已经用过的特征不会再用(其他实现有可能会选重复特征)
    '''

    l_cnt = Counter(label)  # 计数每个类别的样本出现次数
    if len(l_cnt) <= 1:  # 如果只有一种类别了,无需分裂,已经是叶节点
        return label[0]  # 只需记录类别
    if len(label) < self.min_samples_split or depth > self.max_depth:  # 如果达到了最小分裂的样本数或者最大深度的阈值
        return l_cnt.most_common(1)[0][0]  # 则只记录当前样本中最多的类别

    f_idx, max_gain, f_v_index = -1, -1, None  # 准备挑选分裂特征
    for idx in range(len(self.features)):  # 遍历所有特征
        if idx in skip_features:  # 如果当前路径已经用到,不用再算
            continue
        f_gain, fv = self.gain(feature[:, idx], label)  # 计算特征的信息增益,fv是特征每个取值的样本下标

        # if f_gain <= 0: # 如果信息增益不为正,跳过该特征
        #   continue
        if f_idx < 0 or f_gain > max_gain:  # 如果个更好的分裂特征
            f_idx, max_gain, f_v_index = idx, f_gain, fv  # 则记录该特征

        # if f_idx < 0: # 如果没有找到合适的特征,即所有特征都没有信息增益
        #   return l_cnt.most_common(1)[0][0] # 则只记录当前样本中最多的类别

    decision = {}  # 用字典记录每个特征取值所对应的子节点,key是特征取值,value是子节点
    skip_features = set([f_idx] + [f for f in skip_features])  # 子节点要跳过的特征包括当前选择的特征
    for v in f_v_index:  # 遍历特征的每种取值
        decision[v] = self.expand_node(feature[f_v_index[v], :], label[f_v_index[v]],  # 取出该特征取值所对应的样本
                                       depth=depth + 1, skip_features=skip_features)  # 深度+1,递归调用节点分裂
    # 返回一个元组,有三个元素
    # 第一个是选择的特征下标,第二个特征取值和对应的子节点(字典),第三个是到达当前节点的样本中最多的类别
    return (f_idx, decision, l_cnt.most_common(1)[0][0])

def traverse_node(self, node, feature):
    '''
    预测样本时从根节点开始遍历节点,根据特征路由。
    :param node: 当前到达的节点,例如self.root
    :param feature: 长度为m的numpy一维数组
    '''
    assert len(self.features) == len(feature)  # 要求输入样本特征数和模型定义时特征数目一致
    if type(node) is not tuple:  # 如果到达了一个节点是叶节点(不再分裂),则返回该节点类别
        return node
    fv = feature[node[0]]  # 否则取出该节点对应的特征值,node[0]记录了特征的下标
    if fv in node[1]:  # 根据特征值找到子节点,注意需要判断训练节点分裂时到达该节点的样本是否有该特征值(分支)
        return self.traverse_node(node[1][fv], feature)  # 如果有,则进入到子节点继续遍历
    return node[-1]  # 如果没有,返回训练时到达当前节点的样本中最多的类别

def fit(self, feature, label):
    '''
    训练模型
    :param feature:feature为二维numpy(n*m)数组,每行表示一个样本,有m个特征
    :param label:label为一维numpy(n)数组,表示每个样本的分类标签
    '''
    assert len(self.features) == len(feature[0])  # 输入数据的特征数目应该和模型定义时的特征数目相同
    self.root = self.expand_node(feature, label, depth=1)  # 从根节点开始分裂,模型记录根节点

def predict(self, feature):
    '''
    预测
    :param feature:输入feature可以是一个一维numpy数组也可以是一个二维numpy数组
    如果是一维numpy(m)数组则是一个样本,包含m个特征,返回一个类别值
    如果是二维numpy(n*m)数组则表示n个样本,每个样本包含m个特征,返回一个numpy一维数组
    '''
    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])  # 如果是很多个样本

def get_params(self, deep):  # 要调用sklearn的cross_validate需要实现该函数返回所有参数
    return {'classes': self.classes, 'features': self.features,
            'max_depth': self.max_depth, 'min_samples_split': self.min_samples_split,
            'impurity_t': self.impurity_t}

def set_params(self, **parameters):  # 要调用sklearn的GridSearchCV需要实现该函数给类设定所有参数
    for parameter, value in parameters.items():
        setattr(self, parameter, value)
    return self

定义决策树模型,传入算法参数

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)) # 输出准确率


**[0 1 0 ... 0 1 1]  
 accuracy: 0.6964**


此时的准确率为**0.6964**,下面我们进行模型调优。



## 第四步:模型调优


在测试集上对不同的混杂度计算方式、深度、最小分裂阈值进行五折交叉验证。



%%time

best = None # 记录最佳结果
for impurity_t in [‘entropy’, ‘gini’]: # 遍历不纯度的计算方式
for max_depth in range(1, 6): # 遍历最大树深度
for min_samples_split in [50, 100, 200, 500, 1000]: # 遍历节点分裂最小样本数的阈值
DT = DecisionTree(classes=[0,1], features=feature_names, # 定义决策树
max_depth=max_depth, min_samples_split=min_samples_split, impurity_t=impurity_t)
cv_result = cross_validate(DT, x_train, y_train, scoring=(‘accuracy’), cv=5) # 5折交叉验证
cv_acc = np.mean(cv_result[‘test_score’]) # 5折平均准确率
current = (cv_acc, max_depth, min_samples_split, impurity_t) # 记录参数和结果
if best is None or cv_acc > best[0]: # 如果是比当前最佳更好的结果
best = current # 记录最好结果
print(‘better cv_accuracy: {:.4f}, max_depth={}, min_samples_split={}, impurity_t={}’.format(*best)) # 输出准确率和参数
else:
print(‘cv_accuracy: {:.4f}, max_depth={}, min_samples_split={}, impurity_t={}’.format(*current)) # 输出准确率和参数

DT = DecisionTree(classes=[0,1], features=feature_names, max_depth=best[1], min_samples_split=best[2], impurity_t=best[3]) # 取最佳参数
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)) # 输出准确率



> 
> 
> ```
> better cv_accuracy: 0.7257, max_depth=1, min_samples_split=50, impurity_t=entropy
> cv_accuracy: 0.7257, max_depth=1, min_samples_split=100, impurity_t=entropy
> cv_accuracy: 0.7257, max_depth=1, min_samples_split=200, impurity_t=entropy
> cv_accuracy: 0.7257, max_depth=1, min_samples_split=500, impurity_t=entropy
> cv_accuracy: 0.7257, max_depth=1, min_samples_split=1000, impurity_t=entropy
> cv_accuracy: 0.7254, max_depth=2, min_samples_split=50, impurity_t=entropy
> cv_accuracy: 0.7254, max_depth=2, min_samples_split=100, impurity_t=entropy
> cv_accuracy: 0.7254, max_depth=2, min_samples_split=200, impurity_t=entropy
> cv_accuracy: 0.7254, max_depth=2, min_samples_split=500, impurity_t=entropy
> cv_accuracy: 0.7257, max_depth=2, min_samples_split=1000, impurity_t=entropy
> better cv_accuracy: 0.7267, max_depth=3, min_samples_split=50, impurity_t=entropy
> better cv_accuracy: 0.7272, max_depth=3, min_samples_split=100, impurity_t=entropy
> better cv_accuracy: 0.7281, max_depth=3, min_samples_split=200, impurity_t=entropy
> better cv_accuracy: 0.7286, max_depth=3, min_samples_split=500, impurity_t=entropy
> cv_accuracy: 0.7257, max_depth=3, min_samples_split=1000, impurity_t=entropy
> cv_accuracy: 0.7237, max_depth=4, min_samples_split=50, impurity_t=entropy
> cv_accuracy: 0.7252, max_depth=4, min_samples_split=100, impurity_t=entropy
> cv_accuracy: 0.7285, max_depth=4, min_samples_split=200, impurity_t=entropy
> **better cv\_accuracy: 0.7290, max\_depth=4, min\_samples\_split=500, impurity\_t=entropy**
> cv_accuracy: 0.7257, max_depth=4, min_samples_split=1000, impurity_t=entropy
> cv_accuracy: 0.7149, max_depth=5, min_samples_split=50, impurity_t=entropy
> cv_accuracy: 0.7210, max_depth=5, min_samples_split=100, impurity_t=entropy
> cv_accuracy: 0.7254, max_depth=5, min_samples_split=200, impurity_t=entropy
> cv_accuracy: 0.7290, max_depth=5, min_samples_split=500, impurity_t=entropy
> cv_accuracy: 0.7257, max_depth=5, min_samples_split=1000, impurity_t=entropy
> cv_accuracy: 0.7257, max_depth=1, min_samples_split=50, impurity_t=gini
> cv_accuracy: 0.7257, max_depth=1, min_samples_split=100, impurity_t=gini
> cv_accuracy: 0.7257, max_depth=1, min_samples_split=200, impurity_t=gini
> cv_accuracy: 0.7257, max_depth=1, min_samples_split=500, impurity_t=gini
> cv_accuracy: 0.7257, max_depth=1, min_samples_split=1000, impurity_t=gini
> cv_accuracy: 0.7255, max_depth=2, min_samples_split=50, impurity_t=gini
> cv_accuracy: 0.7255, max_depth=2, min_samples_split=100, impurity_t=gini
> cv_accuracy: 0.7255, max_depth=2, min_samples_split=200, impurity_t=gini
> cv_accuracy: 0.7255, max_depth=2, min_samples_split=500, impurity_t=gini
> cv_accuracy: 0.7257, max_depth=2, min_samples_split=1000, impurity_t=gini
> cv_accuracy: 0.7218, max_depth=3, min_samples_split=50, impurity_t=gini
> cv_accuracy: 0.7235, max_depth=3, min_samples_split=100, impurity_t=gini
> cv_accuracy: 0.7250, max_depth=3, min_samples_split=200, impurity_t=gini
> cv_accuracy: 0.7257, max_depth=3, min_samples_split=500, impurity_t=gini
> cv_accuracy: 0.7257, max_depth=3, min_samples_split=1000, impurity_t=gini
> cv_accuracy: 0.7174, max_depth=4, min_samples_split=50, impurity_t=gini
> cv_accuracy: 0.7248, max_depth=4, min_samples_split=100, impurity_t=gini
> cv_accuracy: 0.7261, max_depth=4, min_samples_split=200, impurity_t=gini
> cv_accuracy: 0.7259, max_depth=4, min_samples_split=500, impurity_t=gini
> cv_accuracy: 0.7257, max_depth=4, min_samples_split=1000, impurity_t=gini
> cv_accuracy: 0.7076, max_depth=5, min_samples_split=50, impurity_t=gini
> cv_accuracy: 0.7185, max_depth=5, min_samples_split=100, impurity_t=gini
> cv_accuracy: 0.7207, max_depth=5, min_samples_split=200, impurity_t=gini
> cv_accuracy: 0.7259, max_depth=5, min_samples_split=500, impurity_t=gini
> cv_accuracy: 0.7257, max_depth=5, min_samples_split=1000, impurity_t=gini
> ```
> 
> 


使用max\_depth=4, min\_samples\_split=500, impurity\_t=entropy在训练集上进行训练,并在测试集上预测,将测试预测值与测试集标签对比获得准确率:**显然提升了**。



> 
> [0 1 0 ... 0 1 1]
> 
> 
> accuracy: 0.7171
> 
> 
> Wall time: 1min 19s
> 
> 
> 


也可以调用sklearn的GridSearchCV自动且多线程搜索参数,和上面的流程类似。



%%time

parameters = {‘impurity_t’:[‘entropy’, ‘gini’],
‘max_depth’: range(1, 6),
‘min_samples_split’: [50, 100, 200, 500, 1000]} # 定义需要遍历的参数
DT = DecisionTree(classes=[0,1], features=feature_names) # 定义决策树,可以不传参数,由GridSearchCV传入构建
grid_search = GridSearchCV(DT, parameters, scoring=‘accuracy’, cv=5, verbose=100, n_jobs=4) # 传入模型和要遍历的参数
grid_search.fit(x_train, y_train) # 在所有数据上搜索参数
print(grid_search.best_score_, grid_search.best_params_) # 输出最佳指标和最佳参数

DT = DecisionTree(classes=[0,1], features=feature_names, **grid_search.best_params_) # 取最佳参数
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)) # 输出准确率



Fitting 5 folds for each of 50 candidates, totalling 250 fits
0.7289642831407777 {‘impurity_t’: ‘entropy’, ‘max_depth’: 4, ‘min_samples_split’: 500}
[0 1 0 … 0 1 1]
accuracy: 0.7171
Wall time: 24.6 s


#### 查看节点的特征



best_dt = grid_search.best_estimator_ # 取出最佳模型
print(‘root’, best_dt.features[best_dt.root[0]]) # 输出根节点特征



root brTotalGold


可见前10分钟最能影响胜率的是**红蓝双方的经济差**



for fv in best_dt.root[1]: # 遍历根节点的每种特征取值
print(fv, ‘->’, best_dt.features[best_dt.root[1][fv][0]], ‘-> …’) # 输出下一层特征



9 -> redDragons -> …
1 -> blueTowersDestroyed -> …
3 -> redEliteMonsters -> …
5 -> redTowersDestroyed -> …
2 -> blueTowersDestroyed -> …
4 -> brTowersDestroyed -> …
7 -> redEliteMonsters -> …
8 -> brTowersDestroyed -> …
0 -> brKills -> …
6 -> brTowersDestroyed -> …


根节点这个特征对应取值0-9(我们之前对金币进行了离散化)所对应的下一层的特征...


       



> 
> **ps:**这个其实来自于我们定义的 **expand\_node**函数返回值,
> 
> 
> return (f\_idx, decision, l\_cnt.most\_common(1)[0][0]) ,
> 
> 


**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注大数据)**
![img](https://img-blog.csdnimg.cn/img_convert/60093c6a42dc42f30ef15654c6f2f89c.png)

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

node**函数返回值,
> 
> 
> return (f\_idx, decision, l\_cnt.most\_common(1)[0][0]) ,
> 
> 


**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注大数据)**
[外链图片转存中...(img-mK02aYvE-1713432962792)]

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 24
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值