头歌-机器学习实验 第8次实验 决策树
第1关:什么是决策树
任务描述
本关任务:根据本节课所学知识完成本关所设置的选择题。
相关知识
为了完成本关任务,你需要掌握决策树的相关基础知识。
引例
在炎热的夏天,没有什么比冰镇后的西瓜更能令人感到心旷神怡的了。现在我要去水果店买西瓜,但什么样的西瓜能入我法眼呢?那根据我的个人习惯,在挑西瓜时可能就有这样的脑回路。
假设现在水果店里有3
个西瓜,它们的属性如下:
编号 | 瓤是否够红 | 够不够冰 | 是否便宜 | 是否有籽 |
---|---|---|---|---|
1 | 是 | 否 | 是 | 否 |
2 | 是 | 是 | 否 | 是 |
3 | 否 | 是 | 是 | 否 |
那么根据我的脑回路我会买1
和2
号西瓜。
其实我的脑回路可以看成一棵树,并且这棵树能够帮助我对买不买西瓜这件事做决策,所以它就是一棵决策树。
决策树的相关概念
决策树是一种可以用于分类与回归的机器学习算法,但主要用于分类。用于分类的决策树是一种描述对实例进行分类的树形结构。决策树由结点和边组成,其中结点分为内部结点和叶子结点,内部结点表示一个特征或者属性,叶子结点表示标签(脑回路图中黄色的是内部结点,蓝色的是叶子结点)。
从代码角度来看,决策树其实可以看成是一堆if-else
语句的集合,例如引例中的决策树完全可以看成是如下代码:
if isRed:
if isCold:
if hasSeed:
print("buy")
else:
print("don't buy")
else:
if isCheap:
print("buy")
else:
print("don't buy")
else:
print("don't buy")
因此决策树的一个非常大的优势就是模型的可理解性非常高,甚至可以用来挖掘数据中比较重要的信息。
那么如何构造出一棵好的决策树呢?其实构造决策树时会遵循一个指标,有的是按照信息增益来构建,如ID3算法;有的是信息增益率来构建,如C4.5算法;有的是按照基尼系数来构建的,如CART算法。但不管是使用哪种构建算法,决策树的构建过程通常都是一个递归选择最优特征,并根据特征对训练集进行分割,使得对各个子数据集有一个最好的分类的过程。
这一过程对应着对特征空间的划分,也对应着决策树的构建。一开始,构建决策树的根结点,将所有训练数据都放在根结点。选择一个最优特征,并按照这一特征将训练数据集分割成子集,使得各个子集有一个在当前条件下最好的分类。如果这些子集已经能够被基本正确分类,那么构建叶子结点,并将这些子集分到所对应的叶结点中去;如果还有子集不能被基本正确分类,那么就对这些子集选择新的最优特征,继续对其进行分割,并构建相应的结点。如此递归进行下去,直至所有训练数据子集被基本正确分类,或者没有合适的特征为止。最后每个子集都被分到叶子结点上,即都有了明确的类别。这就构建出了一棵决策树。
编程要求
根据本关所学习到的知识,完成所有选择题。
测试说明
平台会对你的选项进行判断,如果实际输出结果与预期结果相同,则通关;反之,则 GameOver
。
1、下列说法正确的是?(A、B)A、训练决策树的过程就是构建决策树的过程B、ID3算法是根据信息增益来构建决策树C、C4.5算法是根据基尼系数来构建决策树D、决策树模型的可理解性不高2、下列说法错误的是?(A)A、从树的根节点开始,根据特征的值一步一步走到叶子节点的过程是决策树做决策的过程B、决策树只能是一棵二叉树C、根节点所代表的特征是最优特征
第2关:信息熵与信息增益
任务描述
本关任务:掌握什么是信息增益,完成计算信息增益的程序设计。
相关知识
为了完成本关任务,你需要掌握:
-
信息熵;
-
条件熵;
-
信息增益。
信息熵
信息是个很抽象的概念。人们常常说信息很多,或者信息较少,但却很难说清楚信息到底有多少。比如一本五十万字的中文书到底有多少信息量。
直到1948年,香农提出了“信息熵”的概念,才解决了对信息的量化度量问题。信息熵这个词是香农从热力学中借用过来的。热力学中的热熵是表示分子状态混乱程度的物理量。香农用信息熵的概念来描述信源的不确定度。信源的不确定性越大,信息熵也越大。
从机器学习的角度来看,信息熵表示的是信息量的期望值。如果数据集中的数据需要被分成多个类别,则信息量I(xi)
的定义如下(其中xi
表示多个类别中的第i
个类别,p(xi)
数据集中类别为xi
的数据在数据集中出现的概率表示):
I(Xi)=−log2p(xi)
由于信息熵是信息量的期望值,所以信息熵H(X)
的定义如下(其中n
为数据集中类别的数量):
H(X)=−sumi=1np(xi)log2p(xi)
从这个公式也可以看出,如果概率是0
或者是1
的时候,熵就是0
(因为这种情况下随机变量的不确定性是最低的)。那如果概率是0.5
,也就是五五开的时候,此时熵达到最大,也就是1
。(就像扔硬币,你永远都猜不透你下次扔到的是正面还是反面,所以它的不确定性非常高)。所以呢,熵越大,不确定性就越高。
条件熵
在实际的场景中,我们可能需要研究数据集中某个特征等于某个值时的信息熵等于多少,这个时候就需要用到条件熵。条件熵H(Y|X)
表示特征X为某个值的条件下,类别为Y的熵。条件熵的计算公式如下:
H(Y∣X)=sumi=1npiH(Y∣X=xi)
当然条件熵的性质也和熵的性质一样,概率越确定,条件熵就越小,概率越五五开,条件熵就越大。
信息增益
现在已经知道了什么是熵,什么是条件熵。接下来就可以看看什么是信息增益了。所谓的信息增益就是表示我已知条件X
后能得到信息Y
的不确定性的减少程度。
就好比,我在玩读心术。你心里想一件东西,我来猜。我已开始什么都没问你,我要猜的话,肯定是瞎猜。这个时候我的熵就非常高。然后我接下来我会去试着问你是非题,当我问了是非题之后,我就能减小猜测你心中想到的东西的范围,这样其实就是减小了我的熵。那么我熵的减小程度就是我的信息增益。
所以信息增益如果套上机器学习的话就是,如果把特征A
对训练集D
的信息增益记为g(D, A)
的话,那么g(D, A)
的计算公式就是:
g(D,A)=H(D)−H(D,A)
为了更好的解释熵,条件熵,信息增益的计算过程,下面通过示例来描述。假设我现在有这一个数据集,第一列是编号,第二列是性别,第三列是活跃度,第四列是客户是否流失的标签(0
表示未流失,1
表示流失)。
编号 | 性别 | 活跃度 | 是否流失 |
---|---|---|---|
1 | 男 | 高 | 0 |
2 | 女 | 中 | 0 |
3 | 男 | 低 | 1 |
4 | 女 | 高 | 0 |
5 | 男 | 高 | 0 |
6 | 男 | 中 | 0 |
7 | 男 | 中 | 1 |
8 | 女 | 中 | 0 |
9 | 女 | 低 | 1 |
10 | 女 | 中 | 0 |
11 | 女 | 高 | 0 |
12 | 男 | 低 | 1 |
13 | 女 | 低 | 1 |
14 | 男 | 高 | 0 |
15 | 男 | 高 | 0 |
假如要算性别和活跃度这两个特征的信息增益的话,首先要先算总的熵和条件熵。总的熵其实非常好算,就是把标签作为随机变量X
。上表中标签只有两种(0
和1
)因此随机变量X
的取值只有0
或者1
。所以要计算熵就需要先分别计算标签为0
的概率和标签为1
的概率。从表中能看出标签为0
的数据有10
条,所以标签为0
的概率等于2/3
。标签为1
的概率为1/3
。所以熵为:
−(1/3)∗log(1/3)−(2/3)∗log(2/3)=0.9182
接下来就是条件熵的计算,以性别为男的熵为例。表格中性别为男的数据有8
条,这8
条数据中有3
条数据的标签为1
,有5
条数据的标签为0
。所以根据条件熵的计算公式能够得出该条件熵为:
−(3/8)∗log(3/8)−(5/8)∗log(5/8)=0.9543
根据上述的计算方法可知,总熵为:
−(5/15)∗log(5/15)−(10/15)∗log(10/15)=0.9182
性别为男的熵为:
−(3/8)∗log(3/8)−(5/8)∗log(5/8)=0.9543
性别为女的熵为:
−(2/7)∗log(2/7)−(5/7)∗log(5/7)=0.8631
活跃度为低的熵为:
−(4/4)∗log(4/4)−0=0
活跃度为中的熵为:
−(1/5)∗log(1/5)−(4/5)∗log(4/5)=0.7219
活跃度为高的熵为:
−0−(6/6)∗log(6/6)=0
现在有了总的熵和条件熵之后就能算出性别和活跃度这两个特征的信息增益了。
**性别的信息增益=总的熵-(8/15)性别为男的熵-(7/15)性别为女的熵=0.0064
**活跃度的信息增益=总的熵-(6/15)*活跃度为高的熵-(5/15)活跃度为中的熵-(4/15)活跃度为低的熵=0.6776
那信息增益算出来之后有什么意义呢?回到读心术的问题,为了我能更加准确的猜出你心中所想,我肯定是问的问题越好就能猜得越准!换句话来说我肯定是要想出一个信息增益最大(减少不确定性程度最高)的问题来问你。其实ID3
算法也是这么想的。ID3
算法的思想是从训练集D
中计算每个特征的信息增益,然后看哪个最大就选哪个作为当前结点。然后继续重复刚刚的步骤来构建决策树。
编程要求
根据提示,在右侧编辑器补充代码,完成calcInfoGain
函数实现计算信息增益。
calcInfoGain
函数中的参数:
-
feature
:测试用例中字典里的feature
,类型为ndarray
; -
label
:测试用例中字典里的label
,类型为ndarray
; -
index
:测试用例中字典里的index
,即feature
部分特征列的索引。该索引指的是feature
中第几个特征,如index:0
表示使用第一个特征来计算信息增益。
测试说明
平台会对你编写的代码进行测试,期望您的代码根据输入来输出正确的信息增益,以下为其中一个测试用例:
测试输入: {'feature':[[0, 1], [1, 0], [1, 2], [0, 0], [1, 1]], 'label':[0, 1, 0, 0, 1], 'index': 0}
预期输出: 0.419973
提示: 计算log
可以使用NumPy
中的log2
函数
import numpy as npdef calcInfoGain(feature, label, index):'''计算信息增益:param feature:测试用例中字典里的feature,类型为ndarray:param label:测试用例中字典里的label,类型为ndarray:param index:测试用例中字典里的index,即feature部分特征列的索引。该索引指的是feature中第几个特征,如index:0表示使用第一个特征来计算信息增益。:return:信息增益,类型float''' #*********** Begin ***********## 计算熵def calcInfoEntropy(feature, label):'''计算信息熵:param feature:数据集中的特征,类型为ndarray:param label:数据集中的标签,类型为ndarray:return:信息熵,类型float'''label_set = set(label)result = 0for l in label_set:count = 0for j in range(len(label)):if label[j] == l:count += 1# 计算标签在数据集中出现的概率p = count / len(label)# 计算熵result -= p * np.log2(p)return result# 计算条件熵def calcHDA(feature, label, index, value):'''计算信息熵:param feature:数据集中的特征,类型为ndarray:param label:数据集中的标签,类型为ndarray:param index:需要使用的特征列索引,类型为int:param value:index所表示的特征列中需要考察的特征值,类型为int:return:信息熵,类型float'''count = 0# sub_feature和sub_label表示根据特征列和特征值分割出的子数据集中的特征和标签sub_feature = []sub_label = []for i in range(len(feature)):if feature[i][index] == value:count += 1sub_feature.append(feature[i])sub_label.append(label[i])pHA = count / len(feature)e = calcInfoEntropy(sub_feature, sub_label)return pHA * ebase_e = calcInfoEntropy(feature, label)f = np.array(feature)# 得到指定特征列的值的集合f_set = set(f[:, index])sum_HDA = 0# 计算条件熵for value in f_set:sum_HDA += calcHDA(feature, label, index, value)# 计算信息增益return base_e - sum_HDA#*********** End *************#
第3关:使用ID3算法构建决策树
任务描述
本关任务:补充python
代码,完成DecisionTree
类中的fit
和predict
函数。
相关知识
为了完成本关任务,你需要掌握:
-
ID3
算法构造决策树的流程; -
如何使用构造好的决策树进行预测。
ID3算法
ID3
算法其实就是依据特征的信息增益来构建树的。其大致步骤就是从根结点开始,对结点计算所有可能的特征的信息增益,然后选择信息增益最大的特征作为结点的特征,由该特征的不同取值建立子结点,然后对子结点递归执行上述的步骤直到信息增益很小或者没有特征可以继续选择为止。
因此,ID3
算法伪代码如下:
#假设数据集为D,标签集为A,需要构造的决策树为tree
def ID3(D, A):
if D中所有的标签都相同:
return 标签
if 样本中只有一个特征或者所有样本的特征都一样:
对D中所有的标签进行计数
return 计数最高的标签
计算所有特征的信息增益
选出增益最大的特征作为最佳特征(best_feature)
将best_feature作为tree的根结点
得到best_feature在数据集中所有出现过的值的集合(value_set)
for value in value_set:
从D中筛选出best_feature=value的子数据集(sub_feature)
从A中筛选出best_feature=value的子标签集(sub_label)
#递归构造tree
tree[best_feature][value] = ID3(sub_feature, sub_label)
return tree
使用决策树进行预测
决策树的预测思想非常简单,假设现在已经构建出了一棵用来决策是否买西瓜的决策树。
并假设现在在水果店里有这样一个西瓜,其属性如下:
瓤是否够红 | 够不够冰 | 是否便宜 | 是否有籽 |
---|---|---|---|
是 | 否 | 是 | 否 |
那买不买这个西瓜呢?只需把西瓜的属性代入决策树即可。决策树的根结点是瓤是否够红
,所以就看西瓜的属性,经查看发现够红,因此接下来就看够不够冰
。而西瓜不够冰,那么看是否便宜
。发现西瓜是便宜的,所以这个西瓜是可以买的。
因此使用决策树进行预测的伪代码也比较简单,伪代码如下:
#tree表示决策树,feature表示测试数据
def predict(tree, feature):
if tree是叶子结点:
return tree
根据feature中的特征值走入tree中对应的分支
if 分支依然是课树:
result = predict(分支, feature)
return result
编程要求
填写fit(self, feature, label)
函数,实现ID3
算法,要求决策树保存在self.tree
中。其中:
-
feature
:训练集数据,类型为ndarray
,数值全为整数; -
label
:训练集标签,类型为ndarray
,数值全为整数。
填写predict(self, feature)
函数,实现预测功能,并将标签返回,其中:
feature
:测试集数据,类型为ndarray
,数值全为整数。(PS:feature中有多条数据)
测试说明
只需完成fit
与predict
函数即可,程序内部会调用您所完成的fit
函数构建模型并调用predict
函数来对数据进行预测。预测的准确率高于0.92
视为过关。(PS:若self.tree is None
则会打印决策树构建失败)
import numpy as npclass DecisionTree(object):def __init__(self):#决策树模型self.tree = {}def calcInfoGain(self, feature, label, index):'''计算信息增益:param feature:测试用例中字典里的feature,类型为ndarray:param label:测试用例中字典里的label,类型为ndarray:param index:测试用例中字典里的index,即feature部分特征列的索引。该索引指的是feature中第几个特征,如index:0表示使用第一个特征来计算信息增益。:return:信息增益,类型float'''# 计算熵def calcInfoEntropy(label):'''计算信息熵:param label:数据集中的标签,类型为ndarray:return:信息熵,类型float'''label_set = set(label)result = 0for l in label_set:count = 0for j in range(len(label)):if label[j] == l:count += 1# 计算标签在数据集中出现的概率p = count / len(label)# 计算熵result -= p * np.log2(p)return result# 计算条件熵def calcHDA(feature, label, index, value):'''计算信息熵:param feature:数据集中的特征,类型为ndarray:param label:数据集中的标签,类型为ndarray:param index:需要使用的特征列索引,类型为int:param value:index所表示的特征列中需要考察的特征值,类型为int:return:信息熵,类型float'''count = 0# sub_feature和sub_label表示根据特征列和特征值分割出的子数据集中的特征和标签sub_feature = []sub_label = []for i in range(len(feature)):if feature[i][index] == value:count += 1sub_feature.append(feature[i])sub_label.append(label[i])pHA = count / len(feature)e = calcInfoEntropy(sub_label)return pHA * ebase_e = calcInfoEntropy(label)f = np.array(feature)# 得到指定特征列的值的集合f_set = set(f[:, index])sum_HDA = 0# 计算条件熵for value in f_set:sum_HDA += calcHDA(feature, label, index, value)# 计算信息增益return base_e - sum_HDA# 获得信息增益最高的特征def getBestFeature(self, feature, label):max_infogain = 0best_feature = 0for i in range(len(feature[0])):infogain = self.calcInfoGain(feature, label, i)if infogain > max_infogain:max_infogain = infogainbest_feature = ireturn best_featuredef createTree(self, feature, label):# 样本里都是同一个label没必要继续分叉了if len(set(label)) == 1:return label[0]# 样本中只有一个特征或者所有样本的特征都一样的话就看哪个label的票数高if len(feature[0]) == 1 or len(np.unique(feature, axis=0)) == 1:vote = {}for l in label:if l in vote.keys():vote[l] += 1else:vote[l] = 1max_count = 0vote_label = Nonefor k, v in vote.items():if v > max_count:max_count = vvote_label = kreturn vote_label# 根据信息增益拿到特征的索引best_feature = self.getBestFeature(feature, label)tree = {best_feature: {}}f = np.array(feature)# 拿到bestfeature的所有特征值f_set = set(f[:, best_feature])# 构建对应特征值的子样本集sub_feature, sub_labelfor v in f_set:sub_feature = []sub_label = []for i in range(len(feature)):if feature[i][best_feature] == v:sub_feature.append(feature[i])sub_label.append(label[i])# 递归构建决策树tree[best_feature][v] = self.createTree(sub_feature, sub_label)return treedef fit(self, feature, label):''':param feature: 训练集数据,类型为ndarray:param label:训练集标签,类型为ndarray:return: None'''#************* Begin ************#self.tree = self.createTree(feature, label)#************* End **************#def predict(self, feature):''':param feature:测试集数据,类型为ndarray:return:预测结果,如np.array([0, 1, 2, 2, 1, 0])'''#************* Begin ************#result = []def classify(tree, feature):if not isinstance(tree, dict):return treet_index, t_value = list(tree.items())[0]f_value = feature[t_index]if isinstance(t_value, dict):classLabel = classify(tree[t_index][f_value], feature)return classLabelelse:return t_valuefor f in feature:result.append(classify(self.tree, f))return np.array(result)#************* End **************#
第4关:信息增益率
任务描述
本关任务:根据本关所学知识,完成calcInfoGainRatio
函数。
相关知识
为了完成本关任务,你需要掌握:信息增益率
信息增益率
由于在使用信息增益这一指标进行划分时,更喜欢可取值数量较多的特征。为了减少这种偏好可能带来的不利影响,Ross Quinlan
使用了信息增益率这一指标来选择最优划分属性。
信息增益率的数学定义为如下,其中D表示数据集,a表示数据集中的某一列,Gain(D,a)表示D中a的信息增益,V表示a这一列中取值的集合,v表示V中的某种取值,∣D∣表示D中样本的数量,∣Dv∣表示D中a这一列中值等于v的数量。
Gain_ratio(D,a)=−v=1∑V∣D∣∣Dv∣log2∣D∣∣Dv∣Gain(D,a)
从公式可以看出,信息增益率很好算,只是用信息增益除以另一个分母,该分母通常称为固有值。举个例子,还是使用第二关中提到过的数据集,第一列是编号,第二列是性别,第三列是活跃度,第四列是客户是否流失的标签(0
表示未流失,1
表示流失)。
编号 | 性别 | 活跃度 | 是否流失 |
---|---|---|---|
1 | 男 | 高 | 0 |
2 | 女 | 中 | 0 |
3 | 男 | 低 | 1 |
4 | 女 | 高 | 0 |
5 | 男 | 高 | 0 |
6 | 男 | 中 | 0 |
7 | 男 | 中 | 1 |
8 | 女 | 中 | 0 |
9 | 女 | 低 | 1 |
10 | 女 | 中 | 0 |
11 | 女 | 高 | 0 |
12 | 男 | 低 | 1 |
13 | 女 | 低 | 1 |
14 | 男 | 高 | 0 |
15 | 男 | 高 | 0 |
根据第二关已经知道性别的信息增益为0.0064,设a为性别,则有Gain(D,a)=0.0064。由根据数据可知,V=2,假设当v=1时表示性别为男,v=2时表示性别为女,则有∣D∣=15,∣D1∣=8,∣D2∣=7。因此根据信息增益率的计算公式可知Gainratio(D,a)=0.0642。同理可以算出活跃度的信息增益率为0.4328。
编程要求
根据提示,在右侧编辑器补充代码,完成calcInfoGainRatio
函数实现计算信息增益。
calcInfoGainRatio
函数中的参数:
-
feature
:测试用例中字典里的feature
,类型为ndarray
; -
label
:测试用例中字典里的label
,类型为ndarray
; -
index
:测试用例中字典里的index
,即feature
部分特征列的索引。该索引指的是feature
中第几个特征,如index:0
表示使用第一个特征来计算信息增益率。
测试说明
平台会对你编写的代码进行测试,期望您的代码根据输入来输出正确的信息增益,以下为其中一个测试用例:
测试输入: {'feature':[[0, 1], [1, 0], [1, 2], [0, 0], [1, 1]], 'label':[0, 1, 0, 0, 1], 'index': 0}
预期输出: 0.432538
提示: 计算log
可以使用NumPy
中的log2
函数.
import numpy as npdef calcInfoGain(feature, label, index):'''计算信息增益:param feature:测试用例中字典里的feature,类型为ndarray:param label:测试用例中字典里的label,类型为ndarray:param index:测试用例中字典里的index,即feature部分特征列的索引。该索引指的是feature中第几个特征,如index:0表示使用第一个特征来计算信息增益。:return:信息增益,类型float'''# 计算熵def calcInfoEntropy(label):'''计算信息熵:param label:数据集中的标签,类型为ndarray:return:信息熵,类型float'''label_set = set(label)result = 0for l in label_set:count = 0for j in range(len(label)):if label[j] == l:count += 1# 计算标签在数据集中出现的概率p = count / len(label)# 计算熵result -= p * np.log2(p)return result# 计算条件熵def calcHDA(feature, label, index, value):'''计算信息熵:param feature:数据集中的特征,类型为ndarray:param label:数据集中的标签,类型为ndarray:param index:需要使用的特征列索引,类型为int:param value:index所表示的特征列中需要考察的特征值,类型为int:return:信息熵,类型float'''count = 0# sub_feature和sub_label表示根据特征列和特征值分割出的子数据集中的特征和标签sub_feature = []sub_label = []for i in range(len(feature)):if feature[i][index] == value:count += 1sub_feature.append(feature[i])sub_label.append(label[i])pHA = count / len(feature)e = calcInfoEntropy(sub_label)return pHA * ebase_e = calcInfoEntropy(label)f = np.array(feature)# 得到指定特征列的值的集合f_set = set(f[:, index])sum_HDA = 0# 计算条件熵for value in f_set:sum_HDA += calcHDA(feature, label, index, value)# 计算信息增益return base_e - sum_HDAdef calcInfoGainRatio(feature, label, index):'''计算信息增益率:param feature:测试用例中字典里的feature,类型为ndarray:param label:测试用例中字典里的label,类型为ndarray:param index:测试用例中字典里的index,即feature部分特征列的索引。该索引指的是feature中第几个特征,如index:0表示使用第一个特征来计算信息增益。:return:信息增益率,类型float'''#********* Begin *********#info_gain = calcInfoGain(feature, label, index)unique_value = list(set(feature[:, index]))IV = 0for value in unique_value:len_v = np.sum(feature[:, index] == value)IV -= (len_v/len(feature))*np.log2((len_v/len(feature)))return info_gain/IV#********* End *********#
第5关:基尼系数
任务描述
本关任务:根据本关所学知识,完成calcGini
函数。
相关知识
为了完成本关任务,你需要掌握:基尼系数。
基尼系数
在ID3
算法中我们使用了信息增益来选择特征,信息增益大的优先选择。在C4.5
算法中,采用了信息增益率来选择特征,以减少信息增益容易选择特征值多的特征的问题。但是无论是ID3
还是C4.5
,都是基于信息论的熵模型的,这里面会涉及大量的对数运算。能不能简化模型同时也不至于完全丢失熵模型的优点呢?当然有!那就是基尼系数!
CART
算法使用基尼系数来代替信息增益率,基尼系数代表了模型的不纯度,基尼系数越小,则不纯度越低,特征越好。这和信息增益与信息增益率是相反的(它们都是越大越好)。
基尼系数的数学定义为如下,其中D表示数据集,pk表示D
中第k
个类别在D
中所占比例。
Gini(D)=1−sumk=1∣y∣pk2
从公式可以看出,相比于信息增益和信息增益率,计算起来更加简单。举个例子,还是使用第二关中提到过的数据集,第一列是编号,第二列是性别,第三列是活跃度,第四列是客户是否流失的标签(0
表示未流失,1
表示流失)。
编号 | 性别 | 活跃度 | 是否流失 |
---|---|---|---|
1 | 男 | 高 | 0 |
2 | 女 | 中 | 0 |
3 | 男 | 低 | 1 |
4 | 女 | 高 | 0 |
5 | 男 | 高 | 0 |
6 | 男 | 中 | 0 |
7 | 男 | 中 | 1 |
8 | 女 | 中 | 0 |
9 | 女 | 低 | 1 |
10 | 女 | 中 | 0 |
11 | 女 | 高 | 0 |
12 | 男 | 低 | 1 |
13 | 女 | 低 | 1 |
14 | 男 | 高 | 0 |
15 | 男 | 高 | 0 |
从表格可以看出,D中总共有2个类别,设类别为0的比例为p1,则有p1=1510。设类别为1的比例为p2,则有p2=155。根据基尼系数的公式可知Gini(D)=1−(p12+p22)=0.4444。
上面是基于数据集D
的基尼系数的计算方法,那么基于数据集D
与特征a
的基尼系数怎样计算呢?其实和信息增益率的套路差不多。计算公式如下:
Gini(D,a)=sumv=1V∣D∣∣Dv∣Gini(Dv)
还是以用户流失的数据为例,现在算一算性别的基尼系数。设性别男为v=1,性别女为v=2则有∣D∣=15,∣D1∣=8,∣D2∣=7,Gini(D1)=0.46875,Gini(D2)=0.40816。所以Gini(D,a)=0.44048。
编程要求
根据提示,在右侧编辑器补充代码,完成calcGini
函数实现计算信息增益。
calcGini
函数中的参数:
-
feature
:测试用例中字典里的feature
,类型为ndarray
; -
label
:测试用例中字典里的label
,类型为ndarray
; -
index
:测试用例中字典里的index
,即feature
部分特征列的索引。该索引指的是feature
中第几个特征,如index:0
表示使用第一个特征来计算基尼系数。
测试说明
平台会对你编写的代码进行测试,期望您的代码根据输入来输出正确的信息增益,以下为其中一个测试用例:
测试输入: {'feature':[[0, 1], [1, 0], [1, 2], [0, 0], [1, 1]], 'label':[0, 1, 0, 0, 1], 'index': 0}
预期输出: 0.266667
import numpy as npdef calcGini(feature, label, index):'''计算基尼系数:param feature:测试用例中字典里的feature,类型为ndarray:param label:测试用例中字典里的label,类型为ndarray:param index:测试用例中字典里的index,即feature部分特征列的索引。该索引指的是feature中第几个特征,如index:0表示使用第一个特征来计算信息增益。:return:基尼系数,类型float'''#********* Begin *********#def _gini(label):unique_label = list(set(label))gini = 1for l in unique_label:p = np.sum(label == l)/len(label)gini -= p**2return giniunique_value = list(set(feature[:, index]))gini = 0for value in unique_value:len_v = np.sum(feature[:, index] == value)gini += (len_v/len(feature))*_gini(label[feature[:, index] == value])return gini#********* End *********#
第6关:预剪枝与后剪枝
任务描述
本关任务:补充python
代码,完成DecisionTree
类中的fit
和predict
函数。
相关知识
为了完成本关任务,你需要掌握:
-
为什么需要剪枝;
-
预剪枝;
-
后剪枝。
为什么需要剪枝
决策树的生成是递归地去构建决策树,直到不能继续下去为止。这样产生的树往往对训练数据有很高的分类准确率,但对未知的测试数据进行预测就没有那么准确了,也就是所谓的过拟合。
决策树容易过拟合的原因是在构建决策树的过程时会过多地考虑如何提高对训练集中的数据的分类准确率,从而会构建出非常复杂的决策树(树的宽度和深度都比较大)。在之前的实训中已经提到过,模型的复杂度越高,模型就越容易出现过拟合的现象。所以简化决策树的复杂度能够有效地缓解过拟合现象,而简化决策树最常用的方法就是剪枝。剪枝分为预剪枝与后剪枝。
预剪枝
预剪枝的核心思想是在决策树生成过程中,对每个结点在划分前先进行一个评估,若当前结点的划分不能带来决策树泛化性能提升,则停止划分并将当前结点标记为叶结点。
想要评估决策树算法的泛化性能如何,方法很简单。可以将训练数据集中随机取出一部分作为验证数据集,然后在用训练数据集对每个结点进行划分之前用当前状态的决策树计算出在验证数据集上的正确率。正确率越高说明决策树的泛化性能越好,如果在划分结点的时候发现泛化性能有所下降或者没有提升时,说明应该停止划分,并用投票计数的方式将当前结点标记成叶子结点。
举个例子,假如上一关中所提到的用来决定是否买西瓜的决策树模型已经出现过拟合的情况,模型如下:
假设当模型在划分是否便宜
这个结点前,模型在验证数据集上的正确率为0.81
。但在划分后,模型在验证数据集上的正确率降为0.67
。此时就不应该划分是否便宜
这个结点。所以预剪枝后的模型如下:
从上图可以看出,预剪枝能够降低决策树的复杂度。这种预剪枝处理属于贪心思想,但是贪心有一定的缺陷,就是可能当前划分会降低泛化性能,但在其基础上进行的后续划分却有可能导致性能显著提高。所以有可能会导致决策树出现欠拟合的情况。
后剪枝
后剪枝是先从训练集生成一棵完整的决策树,然后自底向上地对非叶结点进行考察,若将该结点对应的子树替换为叶结点能够带来决策树泛化性能提升,则将该子树替换为叶结点。
后剪枝的思路很直接,对于决策树中的每一个非叶子结点的子树,我们尝试着把它替换成一个叶子结点,该叶子结点的类别我们用子树所覆盖训练样本中存在最多的那个类来代替,这样就产生了一个简化决策树,然后比较这两个决策树在测试数据集中的表现,如果简化决策树在验证数据集中的准确率有所提高,那么该子树就可以替换成叶子结点。该算法以bottom-up
的方式遍历所有的子树,直至没有任何子树可以替换使得测试数据集的表现得以改进时,算法就可以终止。
从后剪枝的流程可以看出,后剪枝是从全局的角度来看待要不要剪枝,所以造成欠拟合现象的可能性比较小。但由于后剪枝需要先生成完整的决策树,然后再剪枝,所以后剪枝的训练时间开销更高。
编程要求
填写fit(self, train_feature, train_label, val_featrue, val_label)
函数,实现带后剪枝的ID3
算法,要求决策树保存在self.tree
中。其中:
-
train_feature
:训练集数据,类型为ndarray
,数值全为整数; -
train_label
:训练集标签,类型为ndarray
,数值全为整数; -
val_feature
:验证集数据,类型为ndarray
,数值全为整数; -
val_label
:验证集标签,类型为ndarray
,数值全为整数。
填写predict(self, feature)
函数,实现预测功能,并将标签返回,其中:
feature
:测试集数据,类型为ndarray
,数值全为整数。(PS:feature中有多条数据)
测试说明
只需完成fit
与predict
函数即可,程序内部会调用您所完成的fit
函数构建模型并调用predict
函数来对数据进行预测。预测的准确率高于0.935
视为过关。(PS:若self.tree is None
则会打印决策树构建失败)
import numpy as np
from copy import deepcopyclass DecisionTree(object):def __init__(self):#决策树模型self.tree = {}def calcInfoGain(self, feature, label, index):'''计算信息增益:param feature:测试用例中字典里的feature,类型为ndarray:param label:测试用例中字典里的label,类型为ndarray:param index:测试用例中字典里的index,即feature部分特征列的索引。该索引指的是feature中第几个特征,如index:0表示使用第一个特征来计算信息增益。:return:信息增益,类型float'''# 计算熵def calcInfoEntropy(feature, label):'''计算信息熵:param feature:数据集中的特征,类型为ndarray:param label:数据集中的标签,类型为ndarray:return:信息熵,类型float'''label_set = set(label)result = 0for l in label_set:count = 0for j in range(len(label)):if label[j] == l:count += 1# 计算标签在数据集中出现的概率p = count / len(label)# 计算熵result -= p * np.log2(p)return result# 计算条件熵def calcHDA(feature, label, index, value):'''计算信息熵:param feature:数据集中的特征,类型为ndarray:param label:数据集中的标签,类型为ndarray:param index:需要使用的特征列索引,类型为int:param value:index所表示的特征列中需要考察的特征值,类型为int:return:信息熵,类型float'''count = 0# sub_feature和sub_label表示根据特征列和特征值分割出的子数据集中的特征和标签sub_feature = []sub_label = []for i in range(len(feature)):if feature[i][index] == value:count += 1sub_feature.append(feature[i])sub_label.append(label[i])pHA = count / len(feature)e = calcInfoEntropy(sub_feature, sub_label)return pHA * ebase_e = calcInfoEntropy(feature, label)f = np.array(feature)# 得到指定特征列的值的集合f_set = set(f[:, index])sum_HDA = 0# 计算条件熵for value in f_set:sum_HDA += calcHDA(feature, label, index, value)# 计算信息增益return base_e - sum_HDA# 获得信息增益最高的特征def getBestFeature(self, feature, label):max_infogain = 0best_feature = 0for i in range(len(feature[0])):infogain = self.calcInfoGain(feature, label, i)if infogain > max_infogain:max_infogain = infogainbest_feature = ireturn best_feature# 计算验证集准确率def calc_acc_val(self, the_tree, val_feature, val_label):result = []def classify(tree, feature):if not isinstance(tree, dict):return treet_index, t_value = list(tree.items())[0]f_value = feature[t_index]if isinstance(t_value, dict):classLabel = classify(tree[t_index][f_value], feature)return classLabelelse:return t_valuefor f in val_feature:result.append(classify(the_tree, f))result = np.array(result)return np.mean(result == val_label)def createTree(self, train_feature, train_label):# 样本里都是同一个label没必要继续分叉了if len(set(train_label)) == 1:return train_label[0]# 样本中只有一个特征或者所有样本的特征都一样的话就看哪个label的票数高if len(train_feature[0]) == 1 or len(np.unique(train_feature, axis=0)) == 1:vote = {}for l in train_label:if l in vote.keys():vote[l] += 1else:vote[l] = 1max_count = 0vote_label = Nonefor k, v in vote.items():if v > max_count:max_count = vvote_label = kreturn vote_label# 根据信息增益拿到特征的索引best_feature = self.getBestFeature(train_feature, train_label)tree = {best_feature: {}}f = np.array(train_feature)# 拿到bestfeature的所有特征值f_set = set(f[:, best_feature])# 构建对应特征值的子样本集sub_feature, sub_labelfor v in f_set:sub_feature = []sub_label = []for i in range(len(train_feature)):if train_feature[i][best_feature] == v:sub_feature.append(train_feature[i])sub_label.append(train_label[i])# 递归构建决策树tree[best_feature][v] = self.createTree(sub_feature, sub_label)return tree# 后剪枝def post_cut(self, val_feature, val_label):# 拿到非叶子节点的数量def get_non_leaf_node_count(tree):non_leaf_node_path = []def dfs(tree, path, all_path):for k in tree.keys():if isinstance(tree[k], dict):path.append(k)dfs(tree[k], path, all_path)if len(path) > 0:path.pop()else:all_path.append(path[:])dfs(tree, [], non_leaf_node_path)unique_non_leaf_node = []for path in non_leaf_node_path:isFind = Falsefor p in unique_non_leaf_node:if path == p:isFind = Truebreakif not isFind:unique_non_leaf_node.append(path)return len(unique_non_leaf_node)# 拿到树中深度最深的从根节点到非叶子节点的路径def get_the_most_deep_path(tree):non_leaf_node_path = []def dfs(tree, path, all_path):for k in tree.keys():if isinstance(tree[k], dict):path.append(k)dfs(tree[k], path, all_path)if len(path) > 0:path.pop()else:all_path.append(path[:])dfs(tree, [], non_leaf_node_path)max_depth = 0result = Nonefor path in non_leaf_node_path:if len(path) > max_depth:max_depth = len(path)result = pathreturn result# 剪枝def set_vote_label(tree, path, label):for i in range(len(path)-1):tree = tree[path[i]]tree[path[len(path)-1]] = vote_labelacc_before_cut = self.calc_acc_val(self.tree, val_feature, val_label)# 遍历所有非叶子节点for _ in range(get_non_leaf_node_count(self.tree)):path = get_the_most_deep_path(self.tree)# 备份树tree = deepcopy(self.tree)step = deepcopy(tree)# 跟着路径走for k in path:step = step[k]# 叶子节点中票数最多的标签vote_label = sorted(step.items(), key=lambda item: item[1], reverse=True)[0][0]# 在备份的树上剪枝set_vote_label(tree, path, vote_label)acc_after_cut = self.calc_acc_val(tree, val_feature, val_label)# 验证集准确率高于0.9才剪枝if acc_after_cut > acc_before_cut:set_vote_label(self.tree, path, vote_label)acc_before_cut = acc_after_cutdef fit(self, train_feature, train_label, val_feature, val_label):''':param train_feature:训练集数据,类型为ndarray:param train_label:训练集标签,类型为ndarray:param val_feature:验证集数据,类型为ndarray:param val_label:验证集标签,类型为ndarray:return: None'''#************* Begin ************#self.tree = self.createTree(train_feature, train_label)# 后剪枝self.post_cut(val_feature, val_label)#************* End **************#def predict(self, feature):''':param feature:测试集数据,类型为ndarray:return:预测结果,如np.array([0, 1, 2, 2, 1, 0])'''#************* Begin ************#result = []# 单个样本分类def classify(tree, feature):if not isinstance(tree, dict):return treet_index, t_value = list(tree.items())[0]f_value = feature[t_index]if isinstance(t_value, dict):classLabel = classify(tree[t_index][f_value], feature)return classLabelelse:return t_valuefor f in feature:result.append(classify(self.tree, f))return np.array(result)#************* End **************#
第7关:鸢尾花识别
任务描述
本关任务:使用sklearn
完成鸢尾花分类任务。
相关知识
为了完成本关任务,你需要掌握如何使用sklearn
提供的DecisionTreeClassifier
。
数据简介
鸢尾花数据集是一类多重变量分析的数据集。通过花萼长度,花萼宽度,花瓣长度,花瓣宽度4
个属性预测鸢尾花卉属于(Setosa
,Versicolour
,Virginica
)三个种类中的哪一类(其中分别用0
,1
,2
代替)。
数据集中部分数据与标签如下图所示:
DecisionTreeClassifier
DecisionTreeClassifier
的构造函数中有两个常用的参数可以设置:
criterion
:划分节点时用到的指标。有gini
(基尼系数),entropy
(信息增益)。若不设置,默认为gini
max_depth
:决策树的最大深度,如果发现模型已经出现过拟合,可以尝试将该参数调小。若不设置,默认为None
和sklearn
中其他分类器一样,DecisionTreeClassifier
类中的fit
函数用于训练模型,fit
函数有两个向量输入:
-
X
:大小为[样本数量,特征数量]
的ndarray
,存放训练样本; -
Y
:值为整型,大小为[样本数量]
的ndarray
,存放训练样本的分类标签。
DecisionTreeClassifier
类中的predict
函数用于预测,返回预测标签,predict
函数有一个向量输入:
X
:大小为[样本数量,特征数量]
的ndarray
,存放预测样本。
DecisionTreeClassifier
的使用代码如下:
from sklearn.tree import DecisionTreeClassifier
clf = tree.DecisionTreeClassifier()
clf.fit(X_train, Y_train)
result = clf.predict(X_test)
编程要求
补充python
代码,实现鸢尾花数据的分类任务,其中训练集数据保存在./step7/train_data.csv
中,训练集标签保存在。./step7/train_label.csv
中,测试集数据保存在。./step7/test_data.csv
中。请将对测试集的预测结果保存至。./step7/predict.csv
中。这些csv
文件可以使用pandas
读取与写入。
注意:当使用pandas
读取完csv
文件后,请将读取到的DataFrame
转换成ndarray
类型。这样才能正常的使用fit
和predict
。
示例代码:
import pandas as pd
# as_matrix()可以将DataFrame转换成ndarray
# 此时train_df的类型为ndarray而不是DataFrame
train_df = pd.read_csv('train_data.csv').as_matrix()
数据文件格式如下图所示:
标签文件格式如下图所示:
PS:predict.csv
文件的格式必须与标签文件格式一致。
测试说明
只需将结果保存至./step7/predict.csv
即可,程序内部会检测您的代码,预测准确率高于0.95
视为过关。
#********* Begin *********#
import pandas as pd
from sklearn.tree import DecisionTreeClassifiertrain_df = pd.read_csv('./step7/train_data.csv').as_matrix()
train_label = pd.read_csv('./step7/train_label.csv').as_matrix()
test_df = pd.read_csv('./step7/test_data.csv').as_matrix()dt = DecisionTreeClassifier()
dt.fit(train_df, train_label)
result = dt.predict(test_df)result = pd.DataFrame({'target':result})
result.to_csv('./step7/predict.csv', index=False)#********* End *********#
相关文章:

头歌-机器学习实验 第8次实验 决策树
第1关:什么是决策树 任务描述 本关任务:根据本节课所学知识完成本关所设置的选择题。 相关知识 为了完成本关任务,你需要掌握决策树的相关基础知识。 引例 在炎热的夏天,没有什么比冰镇后的西瓜更能令人感到心旷神怡的了。现…...

Spring和Spring MVC和MyBatis面试题
面试题1:请简述Spring、Spring MVC和MyBatis在整合开发中的作用? 答案: Spring:是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。它提供了强大的依赖注入功能,…...

用vue3写一个AI聊天室
效果图如下: 1、页面布局: <template><div class"body" style"background-color: rgb(244, 245, 248); height: 730px"><div class"container"><div class"right"><div class"…...

photomaker:customizing realistic human photos via stacked id embedding
PhotoMaker: 高效个性化定制人像照片文生图 - 知乎今天分享我们团队最新的工作PhotoMaker的技术细节。该工作开源5天Githubstar数已过6千次,已列入Github官方Trending榜第一位,PaperswithCode热度榜第一位,HuggingFace Spaces趋势榜第一位。项…...

FFmpeg - 如何在Linux上安装支持CUDA的FFmpeg
FFmpeg - 如何在Linux(Ubuntu)上安装支持CUDA的FFmpeg 笔者认为现在的很多“xx教程”只讲干什么不讲为什么,这样即使报错了看官也不知道如何解决。 在安装过程的探索部分会记录我的整个安装过程以及报错和报错的解决办法。 在省流之一步到位的方法部分会省去安装过…...

新火种AI|商汤发布下棋机器人元萝卜,率先深入家庭场景。
作者:小岩 编辑:彩云 如今提及生成式AI(AIGC),已经不算什么新鲜产物了。自2014年GAN神经网络出现,2017年Transformer架构演进,再加上2023年ChatGPT的大火,无不说明生成式AI正在有条…...

CSS实现三栏自适应布局(两边固定,中间自适应)
绝对定位的元素会脱离文档流,它们是相对于包含块(通常是最近的具有相对定位、绝对定位或固定定位属性的父元素)进行定位的。当你把一个绝对定位的元素的高度设置为100%时,它会相对于其包含块的高度来确定自己的高度。如果包含块是…...

MoCo 算法阅读记录
论文地址:🐰 何凯明大神之作,通过无监督对比学习预训练Image Encoder的表征能力。后也被许多VLP算法作为ITC的底层算法来使用。 一方面由于源代码本身并不复杂,但是要求多GPU分布式训练,以及需要下载ImageNet这个大规模…...

华为OD机试 - 数组连续和 - 滑动窗口(Java 2024 C卷 100分)
华为OD机试 2024C卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(A卷B卷C卷)》。 刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试…...

微店micro获得微店micro商品详情,API接口封装系列
微店商品详情API接口封装系列主要涉及注册账号、获取API密钥、选择API接口、发送请求以及处理响应等步骤。以下是详细的流程: 请求示例,API接口接入Anzexi58 一、注册账号并获取API密钥 首先,你需要在微店开放平台注册一个账号。注册成功后…...

C语言中的数据结构--链表的应用1(2)
前言 上一节我们学习了链表的概念以及链表的实现,那么本节我们就来了解一下链表具体有什么用,可以解决哪些实质性的问题,我们借用习题来加强对链表的理解,那么废话不多说,我们正式进入今天的学习 单链表相关经典算法O…...

.Net6 使用Autofac进行依赖注入
一、背景 刚接触.net 6,记录一下在.net6上是怎么使用Autofac进行动态的依赖注入的 二、注入方式 1、新建一个webapi项目,框架选择net 6 2、引用Nuget包---Autofac.Extensions.Dependency 3、在Program.cs上添加如下代码 //依赖注入 builder.Host.Us…...

第十二届蓝桥杯省赛真题(C/C++大学B组)
目录 #A 空间 #B 卡片 #C 直线 #D 货物摆放 #E 路径 #F 时间显示 #G 砝码称重 #H 杨辉三角形 #I 双向排序 #J 括号序列 #A 空间 #include <bits/stdc.h> using namespace std;int main() {cout<<256 * 1024 * 1024 / 4<<endl;return 0; } #B 卡片…...

DC40V降压恒压芯片H4120 40V转5V 3A 40V降压12V 车充降压恒压控制器
同步整流恒压芯片在现代电子设备中发挥着重要作用,为各种设备提供了稳定、高效的电源管理解决方案。 同步整流恒压芯片是一种电源管理芯片,它能够在不同电压输入条件下保持输出电压恒定。这种芯片广泛应用于各种电子设备中,如通讯设备、液晶…...

2、Qt UI控件 -- qucsdk项目使用
前言:上一篇文章讲了qucsdk的环境部署,可以在QDesigner和Qt Creator中看到qucsdk控件,这一篇来讲下在项目中使用qucsdk库中的控件。 一、准备材料 要想使用第三方库,需要三个先决条件, 1、控件的头文件 2、动/静态链…...

MATLAB算法实战应用案例精讲-【人工智能】AIGC概念三部曲(三)
目录 前言 算法原理 大模型 什么是AIGC? AIGC和Chat GPT的关系 常见的AIGC应用...

外汇110:外汇交易不同货币类别及交易注意事项!
外汇市场是一个庞大而复杂的市场,其中有各种各样的货币品种。对于外汇投资者来说,了解外汇品种的特性和走势是比较重要的。1. 货币种类 外汇市场中的货币品种可以分为主要货币、次要货币和外围货币。 主要货币:主要指美元、欧元、英镑、日元、…...

gerrit 拉取失败
在浏览器gerrit的设置界面设置的邮箱地址和在命令行使用git config --gloable user.email设置的邮箱地址必须保持一致吗 在浏览器gerrit的设置界面设置的邮箱地址和在命令行使用git config --global user.email设置的邮箱地址并不一定需要保持一致。这两个邮箱地址是独立的&am…...

大数据行业英语单词巩固20240410
20240410 Communication - 沟通 Example: Effective communication is essential for project success. 有效的沟通对于项目的成功至关重要。 Collaboration - 协作 Example: Team collaboration is crucial in achieving our goals. 团队协作对于实现我们的目标至关重要。 …...

天软特色因子看板 (2024.4 第3期)
该因子看板跟踪天软特色因子A05005(近一月单笔流出金额占比(%),该因子为近一月单笔流出金额占比(% 均值因子,用以刻画下跌时的 单成交中可能存在的抄底现象 今日为该因子跟踪第3期,跟踪其在SH000852 (中证1000) 中的表现,要点如下…...

使用QT 开发不规则窗体
使用QT 开发不规则窗体 不规则窗体贴图法的不规则窗体创建UI模板创建一个父类创建业务窗体main函数直接调用user_dialog创建QSS文件 完整的QT工程 不规则窗体 QT中开发不规则窗体有两种方法:(1)第一种方法,使用QWidget::setMask函…...

如何构建企业经营所需的商业智能(BI)能力
构建企业经营所需的商业智能(BI)能力是一项涉及诸多关键环节与细致考量的系统工程,通过科学的数据处理、分析与应用,赋能企业实现精准决策,提升运营效率,优化业务流程,并在竞争激烈的市场环境中…...

【vue】watch监听取不到this指向的数?
今天同事问我,watch里this指向的数值,别的地方却可以打印出来。工具也能看到数值,但打印出来却是undifined,先看看代码: 懒得打字了直接上截图吧 ps: 在Vue组件中,如果你在watch选项中访问this…...

Ubuntu-22.04安装VMware虚拟机并安装Windows10
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、VMware是什么?二、安装VMware1.注册VMware账号2.下载虚拟机3.编译vmmon&vmnet4.加载module5.安装bundle 三、安装Windows101.基础配置2.进阶…...

ELK企业日志分析系统介绍
前言 随着企业级应用系统日益复杂,随之产生的海量日志数据。传统的日志管理和分析手段,难以做到高效检索、实时监控以及深度挖掘潜在价值。在此背景下,ELK日志分析系统应运而生。本文将从ELK 日志分析系统的原理、架构及其在实践中的应用做相…...

在C#中读取写入字节流与读取写入二进制数据, 有何差异?
在C#中,读取和写入字节流与读取和写入二进制数据有些许不同,尽管它们在某些情况下可能会重叠使用。以下是它们之间的主要区别: 读取和写入字节流: 读取和写入字节流通常指的是处理文件或流中的原始字节数据。在C#中,可…...

数据库相关知识总结
一、数据库三级模式 三个抽象层次: 1. 视图层:最高层次的抽象,描述整个数据库的某个部分的数据 2. 逻辑层:描述数据库中存储的数据以及这些数据存在的关联 3. 物理层:最低层次的抽象,描述数据在存储器中时如…...

【汇编语言实战】输出数组中特定元素
C语言描述: #include <stdio.h> int main() {int a[]{1,2,3,4,5,6};printf("%d",a[3]); }汇编语言: include irvine32.inc .data arr dword 1,2,3,4,5,6 num dword 1 ;输出第二个元素 .code main proc mov esi,offset arr mov edx,nu…...

WordPress LayerSlider插件SQL注入漏洞复现(CVE-2024-2879)
0x01 产品简介 WordPress插件LayerSlider是一款可视化网页内容编辑器、图形设计软件和数字视觉效果应用程序,全球活跃安装量超过 1,000,000 次。 0x02 漏洞概述 WordPress LayerSlider插件版本7.9.11 – 7.10.0中,由于对用户提供的参数转义不充分以及缺少wpdb::prepare(),…...

MOS管的判别符号记忆与导通条件
参考链接 MOS管的判别与导通条件 (qq.com)https://mp.weixin.qq.com/s?__bizMzU3MDU1Mzg2OQ&mid2247520228&idx1&sn5996780179fbf01f66b5db0c71622ac3&chksmfcef6c86cb98e590e3d3734ee27797bdded17b6b648b3b0d3b1599e8a4496a1fa4e457be6516&mpshare1&…...