CART决策树----基尼指数划分

article/2025/10/31 4:36:50

文章目录

  • CART决策树----基尼指数划分
    • 一.决策树算法的构建
    • 二.划分选择——基尼指数
    • 三.剪枝处理
      • 1.预剪枝
      • 2.后剪枝
    • 四.算法代码

CART决策树----基尼指数划分

一.决策树算法的构建

一般的,一棵决策树包含一个根节点,若干个内部结点和若干个叶结点;叶结点对应于决策结果,其他每个结点则对应于一个属性测试;每个结点包含的样本集合根据测试属性的结果被划分到子结点中;根节点包含样本全集。从根节点到每个叶节点的路径对应了一个判定测试序列。决策树学习的目的是为了产生一棵泛化能力强,即处理未见例能力强的决策树,其基本流程遵循简单而直观的分而治之策略
————from 西瓜书

决策树算法伪代码:
在这里插入图片描述决策树的生成是一个递归的过程,在决策树生成算法的过程中,有三种情形需要递归返回:

  • (1)当前结点包含的样本全部属于同一类别,无需划分,例如当前结点全是正例(好瓜):设置为叶子结点,返回当前集合的类别
  • (2)当前属性集为空,或是所有样本在所有属性上取值相同,无法划分,例如对所有类别属性的划分都已经结束,无法进一步划分,或者比如色泽青绿的瓜其他属性都一样,也不必继续划分。:把当前结点标记为叶子结点,并将其类别设置为该节点所含样本最多的类别。
  • (3)当前结点包含的样本集合为空,不能划分:当前结点设置为叶子节点,单将其类别设置为父节点所含样本中最多的类别。

在这里插入图片描述

二.划分选择——基尼指数

在决策树的建立过程当中,涉及到很多对当前结点集合的划分操作,而如何选择最优划分属性是决策树算法的关键问题之一。
一般而言,随着划分过程的不断进行,我们希望决策树的分支节点所包含的样本尽可能属于同一类别,即结点的 纯度(purity) 越来越高。

基尼指数:CART决策树使用基尼指数(Gini index)来选择划分属性:
G i n i ( D ) = 1 − ∑ k = 1 ∣ y ∣ p k 2 Gini(D)=1-\sum_{k=1}^{|y|}{p_k}^2 Gini(D)=1k=1ypk2
直观来说,Gini(D)反映了从数据集D中随机抽取两个样本,其类别标记不一致的概率,因此Gini(D)越小,则数据集D的纯度越高。
属性a的基尼指数定义为:
G i n i _ i n d e x ( D , a ) = ∑ v = 1 V ∣ D v ∣ ∣ D ∣ G i n i ( D v ) Gini\_index(D,a)=\sum_{v=1}^V\frac{|D^v|}{|D|}Gini(D^v) Gini_index(D,a)=v=1VDDvGini(Dv)
于是在候选属性集A中,选择哪个使得划分后基尼指数最小的属性作为最优划分属性,即:
a ∗ = a r g m i n G i n i _ i n d e x ( D , a ) a*=arg\space min \space Gini\_index(D,a) a=arg min Gini_index(D,a)

西瓜数据集如下:

编号色泽根蒂敲声纹理脐部触感好瓜
0青绿蜷缩浊响清晰凹陷硬滑
1乌黑蜷缩沉闷清晰凹陷硬滑
2乌黑蜷缩浊响清晰凹陷硬滑
3青绿蜷缩沉闷清晰凹陷硬滑
4浅白蜷缩浊响清晰凹陷硬滑
5青绿稍蜷浊响清晰稍凹软粘
6乌黑稍蜷浊响稍糊稍凹软粘
7乌黑稍蜷浊响清晰稍凹硬滑
8乌黑稍蜷沉闷稍糊稍凹硬滑
9青绿硬挺清脆清晰平坦软粘
10浅白硬挺清脆模糊平坦硬滑
11浅白蜷缩浊响模糊平坦软粘
12青绿稍蜷浊响稍糊凹陷硬滑
13浅白稍蜷沉闷稍糊凹陷硬滑
14乌黑稍蜷浊响清晰稍凹软粘
15浅白蜷缩浊响模糊平坦硬滑
16青绿蜷缩沉闷稍糊稍凹硬滑

我们来模拟一下第一次根据基尼指数选择最后划分属性的过程:
假如我们选择的训练集为以下编号的数据:
[0, 1, 2, 3, 5, 6, 9, 13, 14, 15, 16]
我们以对色泽的基尼指数计算为例:
色泽属性中对应的特征有:青绿,乌黑,浅白
在训练集中:

  • 青绿的个数为5个,其中是好瓜的有3个
  • 乌黑的个数为4个,其中是好瓜的有4个
  • 浅白的个数为2个,其中是好瓜的有0个
    据此,由基尼指数公式,我们可以计算D中的Gini(D,色泽):
    ( 1 − ( 3 5 ) 2 − ( 2 5 ) 2 ) ∗ 5 11 + ( 1 − ( 3 4 ) 2 − ( 1 4 ) 2 ) ∗ 4 11 = 0.35454545... (1-(\frac{3}{5})^2-(\frac{2}{5})^2)*{\frac{5}{11}}+(1-(\frac{3}{4})^2-(\frac{1}{4})^2)*{\frac{4}{11}}=0.35454545... (1(53)2(52)2)115+(1(43)2(41)2)114=0.35454545...
    将训练集的各项属性的基尼指数计算得出后:
    在这里插入图片描述
    最终数值最小的“脐部”作为最优划分属性。

根据“脐部”属性特征的不同,按照脐部为:凹陷,稍凹,平坦,将数据集分为三个子集,也就是构建出决策树的三个子节点。再以每一个子节点为数据集,在排除脐部以外的属性集中,选择出下一个最优划分属性来进行进一步的划分或由递归返回条件变为叶子节点并得出分类标记。依次类推,最终将在递归的划分中创建出整颗决策树。其中将数据集分类再处理再分类的过程体现了分而治之的思想。
在这里插入图片描述

三.剪枝处理

剪枝(pruning)是决策树算法对付”过拟合“的主要手段

1.预剪枝

预剪枝是指在决策树生成过程中,对每个结点在划分前先进行估计,若当前结点的划分不能带来决策树泛化性能的提升,则停止划分并将当前结点标记为叶节点,其类型标记为当前结点数据集中总数最多的类别。
预剪枝可以时决策树很多分支不进行展开,降低了过拟合的风险,同时还显著减少了决策树的训练时间开销和测试时间开销。但另一方面,有些分支的当前划分虽然不能提升泛化性能,甚至可能导致泛化性能下降,但在其基础上进行的后续划分却有可能导致泛化性能显著提升。预剪枝基于贪心本质禁止这些分支展开,给预剪枝决策树带来了欠拟合的风险。
在这里插入图片描述

2.后剪枝

后剪枝是先从训练集生成一棵完整的决策树,然后自底向上地对非叶节点进行考察,若将该节点对应的子树替换成叶节点能带来决策树泛化性能的提升,则将该子树替换为叶节点。
后剪枝决策树通常比预剪枝决策树保留了更多的分支。一般情形下,后剪枝决策树的欠拟合风险很小,泛化性能往往优于预剪枝决策树。但是后剪枝过程是在生成完全决策树之后进行的,并且自底向上地对树中的所有非叶节点进行逐一考察,因此其训练时间开销比未剪枝决策树和预剪枝决策树都要大得多,也就算法的时间复杂度往往比较大。

在这里插入图片描述

四.算法代码

算法代码参考了博文:https://blog.csdn.net/m0_37822685/article/details/100055766

import numpy as np
import matplotlib.pyplot as plt
from pylab import *
import operator# 特征字典,后面用到了好多次,干脆当全局变量了
featureDic = {'色泽': ['浅白', '青绿', '乌黑'],'根蒂': ['硬挺', '蜷缩', '稍蜷'],'敲声': ['沉闷', '浊响', '清脆'],'纹理': ['清晰', '模糊', '稍糊'],'脐部': ['凹陷', '平坦', '稍凹'],'触感': ['硬滑', '软粘']}# ***********************画图***********************
# **********************start***********************
# 详情参见机器学习实战决策树那一章# 定义文本框和箭头格式
decisionNode = dict(boxstyle="sawtooth", fc="0.8")
leafNode = dict(boxstyle="round4", fc="0.8")
arrow_args = dict(arrowstyle="<-")
mpl.rcParams['font.sans-serif'] = ['SimHei']  # 没有这句话汉字都是口口
# mpl.rcParams['axes.unicode_minus'] = False  # 解决保存图像是负号'-'显示为方块的问题def plotMidText(cntrPt, parentPt, txtString):xMid = (parentPt[0] - cntrPt[0]) / 2.0 + cntrPt[0]yMid = (parentPt[1] - cntrPt[1]) / 2.0 + cntrPt[1]createPlot.ax1.text(xMid, yMid, txtString, fontsize=20)def plotNode(nodeTxt, centerPt, parentPt, nodeType):  # 绘制带箭头的注解createPlot.ax1.annotate(nodeTxt,xy=parentPt,xycoords="axes fraction",xytext=centerPt,textcoords="axes fraction",va="center",ha="center",bbox=nodeType,arrowprops=arrow_args,fontsize=20)def getNumLeafs(myTree):  # 获取叶节点的数目numLeafs = 0firstStr = list(myTree.keys())[0]secondDict = myTree[firstStr]for key in secondDict.keys():if type(secondDict[key]).__name__ == 'dict':numLeafs += getNumLeafs(secondDict[key])else:numLeafs += 1return numLeafsdef getTreeDepth(myTree):  # 获取树的层数maxDepth = 0firstStr = list(myTree.keys())[0]secondDict = myTree[firstStr]for key in secondDict.keys():if type(secondDict[key]).__name__ == 'dict':thisDepth = 1 + getTreeDepth(secondDict[key])else:thisDepth = 1if thisDepth > maxDepth: maxDepth = thisDepthreturn maxDepthdef plotTree(myTree, parentPt, nodeTxt):numLeafs = getNumLeafs(myTree)getTreeDepth(myTree)firstStr = list(myTree.keys())[0]cntrPt = (plotTree.xOff + (1.0 + float(numLeafs)) / 2.0 / plotTree.totalW,plotTree.yOff)plotMidText(cntrPt, parentPt, nodeTxt)plotNode(firstStr, cntrPt, parentPt, decisionNode)secondDict = myTree[firstStr]plotTree.yOff = plotTree.yOff - 1.0 / plotTree.totalDfor key in secondDict.keys():if type(secondDict[key]).__name__ == 'dict':plotTree(secondDict[key], cntrPt, str(key))else:plotTree.xOff = plotTree.xOff + 1.0 / plotTree.totalWplotNode(secondDict[key], (plotTree.xOff, plotTree.yOff),cntrPt, leafNode)plotMidText((plotTree.xOff, plotTree.yOff), cntrPt, str(key))plotTree.yOff = plotTree.yOff + 1.0 / plotTree.totalDdef createPlot(inTree):fig = plt.figure(1, figsize=(600, 30), facecolor='white')fig.clf()axprops = dict(xticks=[], yticks=[])createPlot.ax1 = plt.subplot(111, frameon=False, **axprops)plotTree.totalW = float(getNumLeafs(inTree))plotTree.totalD = float(getTreeDepth(inTree))plotTree.xOff = -0.5 / plotTree.totalWplotTree.yOff = 1.0plotTree(inTree, (0.5, 1.0), '')plt.show()
# ***********************画图***********************
# ***********************end************************def getDataSet():"""get watermelon data set 3.0 alpha.:return: 训练集合剪枝集以及特征列表。"""# 也可以直接从dataSet = [['青绿', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', '好瓜'],['乌黑', '蜷缩', '沉闷', '清晰', '凹陷', '硬滑', '好瓜'],['乌黑', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', '好瓜'],['青绿', '蜷缩', '沉闷', '清晰', '凹陷', '硬滑', '好瓜'],['浅白', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', '好瓜'],['青绿', '稍蜷', '浊响', '清晰', '稍凹', '软粘', '好瓜'],['乌黑', '稍蜷', '浊响', '稍糊', '稍凹', '软粘', '好瓜'],['乌黑', '稍蜷', '浊响', '清晰', '稍凹', '硬滑', '好瓜'],['乌黑', '稍蜷', '沉闷', '稍糊', '稍凹', '硬滑', '坏瓜'],['青绿', '硬挺', '清脆', '清晰', '平坦', '软粘', '坏瓜'],['浅白', '硬挺', '清脆', '模糊', '平坦', '硬滑', '坏瓜'],['浅白', '蜷缩', '浊响', '模糊', '平坦', '软粘', '坏瓜'],['青绿', '稍蜷', '浊响', '稍糊', '凹陷', '硬滑', '坏瓜'],['浅白', '稍蜷', '沉闷', '稍糊', '凹陷', '硬滑', '坏瓜'],['乌黑', '稍蜷', '浊响', '清晰', '稍凹', '软粘', '坏瓜'],['浅白', '蜷缩', '浊响', '模糊', '平坦', '硬滑', '坏瓜'],['青绿', '蜷缩', '沉闷', '稍糊', '稍凹', '硬滑', '坏瓜']]features = ['色泽', '根蒂', '敲声', '纹理', '脐部', '触感']# #得到特征值字典,本来用这个生成的特征字典,还是直接当全局变量方便# featureDic = {}# for i in range(len(features)):#     featureList = [example[i] for example in dataSet]#     uniqueFeature = list(set(featureList))#     featureDic[features[i]] = uniqueFeature# 每种特征的属性个数numList = []  # [3, 3, 3, 3, 3, 2]for i in range(len(features)):numList.append(len(featureDic[features[i]]))# # 编码,把文字替换成数字。用1、2、3表示同种特征的不同类型# newDataSet = []# for dataVec in dataSet:  # 第一每一个数据#     dataNum = dataVec[-1]  # 保存数据中类别部分#     newData = []#     for i in range(len(dataVec) - 1):  # 值为字符的每一列#         for j in range(numList[i]):  # 对应列的特征的每一类#             if dataVec[i] == featureDic[features[i]][j]:#                 newData.append(j + 1)#     newData.append(dataNum)  # 编码好的部分和原来的数值部分合并#     newDataSet.append(newData)newDataSet = np.array(dataSet)# 得到训练数据集trainIndex = [0, 1, 2, 3, 5, 6, 9, 13, 14, 15, 16]trainDataSet = newDataSet[trainIndex]# 得到剪枝数据集pruneIndex = [4, 7, 8, 10, 11, 12]pruneDataSet = newDataSet[pruneIndex]return np.array(dataSet), trainDataSet, pruneDataSet, features# 计算基尼指数
def calGini(dataArr):"""calculate information entropy.:param dataArr::param classArr::return: Gini"""numEntries = dataArr.shape[0] #shape [0] 表示行数,即数据集样本总数classArr = dataArr[:, -1] #表示是好瓜还是坏瓜uniqueClass = list(set(classArr))Gini = 1.0for c in uniqueClass:Gini -= (len(dataArr[dataArr[:, -1] == c]) / float(numEntries)) ** 2return Ginidef splitDataSet(dataSet, ax, value):"""按照给点的属性ax和其中一种取值value来划分数据。当属性类型为标称数据时,返回一个属性值都为value的数据集。input:dataSet: 输入数据集,形状为(m,n)表示m个数据,前n-1列个属性,最后一列为类型。ax:属性类型value: 标称型时为1、2、3等。数值型为形如0.123的数。return:标称型dataSet返回第ax个属性中值为value组成的集合"""return np.delete(dataSet[dataSet[:, ax] == value], ax, axis=1)def calSplitGin(dataSet, ax, labels):"""计算给定数据dataSet在属性ax上的基尼指数。input:dataSet:输入数据集,形状为(m,n)表示m个数据,前n-1列个属性,最后一列为类型。labelList:属性列表,如['色泽', '根蒂', '敲声', '纹理', '脐部', '触感']ax: 选择用来计算信息增益的属性。0表示第一个属性,1表示第二个属性等。return:Gini:基尼指数"""newGini = 0.0  # 划分完数据后的基尼指数# 对每一种属性for j in featureDic[ax]:axIndex = labels.index(ax)subDataSet = splitDataSet(dataSet, axIndex, j)prob = len(subDataSet) / float(len(dataSet))if prob != 0:  # prob为0意味着dataSet的ax属性中,没有第j+1种值newGini += prob * calGini(subDataSet)return newGinidef chooseBestSplit(dataSet, labelList):"""得到基尼指数最小的属性作为最有划分属性。input:dataSetlabelListreturn:bestFeature: 使得到最大增益划分的属性。"""bestGain = 1bestFeature = -1n = dataSet.shape[1]# 对每一个特征for i in range(n - 1):newGini = calSplitGin(dataSet, labelList[i], labelList)print(f"{labelList[i]}   {newGini}")if newGini < bestGain:bestFeature = ibestGain = newGinireturn bestFeaturedef majorityCnt(classList):classCount = {}for vote in classList:if vote not in classCount:classCount[vote] = 0classCount[vote] += 1# classCount.items()将字典的key-value对变成元组对,如{'a':1, 'b':2} -> [('a',1),('b',2)]# operator.itemgetter(1)按照第二个元素次序进行排序# reverse=True表示从大大到小。[('b',2), ('a',1)]sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)return sortedClassCount[0][0]   # 返回第0个元组的第0个值def createTree(dataSet, labels):"""通过信息增益递归创造一颗决策树。input:labelsdataSetreturn:myTree: 返回一个存有树的字典"""classList = dataSet[:, -1]# 如果基尼指数为0,即D中样本全属于同一类别,返回if calGini(dataSet) == 0:return dataSet[0][-1]# 属性值为空,只剩下类标签if len(dataSet[0]) == 1:return majorityCnt(classList)# 得到增益最大划分的属性、值bestFeatIndex = chooseBestSplit(dataSet, labels)  # bestFeat 是最优划分属性的坐标bestFeatLabel = labels[bestFeatIndex] #获得最优属性print(f"最优属性为:{bestFeatLabel}")myTree = {bestFeatLabel: {}}  # 创建字典,即树的节点。# 生成子树的时候要将已遍历的属性删去。数值型不要删除。labelsCopy = labels[:]del (labelsCopy[bestFeatIndex])uniqueVals = featureDic[bestFeatLabel]  # 最好的特征的类别列表for value in uniqueVals:  # 标称型的属性值有几种,就要几个子树。# Python中列表作为参数类型时,是按照引用传递的,要保证同一节点的子节点能有相同的参数。subLabels = labelsCopy[:]    # subLabels = 注意要用[:],不然还是引用subDataSet = splitDataSet(dataSet, bestFeatIndex, value)print(subDataSet)print("----------")if len(subDataSet) != 0:myTree[bestFeatLabel][value] = createTree(subDataSet, subLabels)else:# 计算D中样本最多的类myTree[bestFeatLabel][value] = majorityCnt(classList)return myTreedef classify(data, featLabels, Tree):"""通过决策树对一条数据分类:param featLabels::param data::param Tree::return: 分类"""firstStr = list(Tree.keys())[0]  # 父节点secondDict = Tree[firstStr]  # 父节点下的子树,即子字典featIndex = featLabels.index(firstStr)  # 当前属性标识的位置classLabel = ""for key in secondDict.keys():  # 遍历该属性下的不同类if data[featIndex] == key:  # 如果数据中找到了匹配的属性类别# 如果不是叶子节点,继续向下遍历if type(secondDict[key]).__name__ == 'dict':classLabel = classify(data, featLabels, secondDict[key])# 如果是叶子节点,返回该叶子节点的类型else:classLabel = secondDict[key]return classLabeldef calAccuracy(dataSet, labels, Tree):"""计算已有决策树的精度:param dataSet::param labels: ['色泽', '根蒂', '敲声', '纹理', '脐部', '触感']:param Tree::return: 决策树精度"""cntCorrect = 0size = len(dataSet)for i in range(size):pre = classify(dataSet[i], labels, Tree)if pre == dataSet[i][-1]:cntCorrect += 1return cntCorrect / float(size)def cntAccNums(dataSet, pruneSet):"""用于剪枝,用dataSet中多数的类作为节点类,计算pruneSet中有多少类是被分类正确的,然后返回正确分类的数目。:param dataSet: 训练集:param pruneSet: 测试集:return: 正确分类的数目"""nodeClass = majorityCnt(dataSet[:, -1])rightCnt = 0for vect in pruneSet:if vect[-1] == nodeClass:rightCnt += 1return rightCntdef prePruning(dataSet, pruneSet, labels):"""每到一个节点要划分的时候:1. 用这个节点上数据投票得出这个节点的类,即是"好瓜"还是"坏瓜"。2. 用这个投票出来的类计算测试集中正确的点数。3. 尝试计算一个节点向下划分时测试点的正确数。假如,当前属性为"脐部",有三种"凹陷","稍凹","平坦",则可将训练集和测试集按照这三种属性值分为三部分,分别计算分类正确的点数并求和。4 若尝试划分得到的正确点数少于不划分时得到的正确点数,则返回不划分时节点的类,否则继续划分。:param dataSet: 训练数据集:param pruneSet: 预剪枝数据集:param labels:  属性标签:return:"""classList = dataSet[:, -1]if calGini(dataSet) == 0:return dataSet[0][-1]if len(dataSet[0]) == 1:return majorityCnt(classList)# 获取最好特征bestFeat = chooseBestSplit(dataSet, labels)bestFeatLabel = labels[bestFeat]# 计算初始正确率baseRightNums = cntAccNums(dataSet, pruneSet)# 得到最好划分属性取值features = featureDic[bestFeatLabel]# 计算尝试划分节点时的正确率splitRightNums = 0.0for value in features:# 每个属性取值得到的子集subDataSet = splitDataSet(dataSet, bestFeat, value)if len(subDataSet) != 0:# 把用来剪枝的子集也按照相应属性值划分下去subPruneSet = splitDataSet(pruneSet, bestFeat, value)splitRightNums += cntAccNums(subDataSet, subPruneSet)if baseRightNums < splitRightNums:  # 如果不划分的正确点数少于尝试划分的点数,则继续划分。myTree = {bestFeatLabel: {}}else:return majorityCnt(dataSet[:, -1])  # 否则,返回不划分时投票得到的类# 以下代码和不预剪枝的代码大致相同,一点不同在于每次测试集也要参与划分。for value in features:subLabels = labels[:]subDataSet = splitDataSet(dataSet, bestFeat, value)subPruneSet = splitDataSet(pruneSet, bestFeat, value)if len(subDataSet) != 0:myTree[bestFeatLabel][value] = prePruning(subDataSet, subPruneSet, subLabels)else:# 计算D中样本最多的类myTree[bestFeatLabel][value] = majorityCnt(classList)return myTreedef postPruning(dataSet, pruneSet, labels):"""后剪枝的思想就是,在决策树每一条分支到达叶子节点时,分别计算剪枝和不剪枝时,位于该节点上的测试数据,被正确判定的数量孰大孰小,以此为依据来决定是否剪枝。:param dataSet::param pruneSet::param labels::return:"""classList = dataSet[:, -1]# 如果基尼指数为0,即D中样本全属于同一类别,返回if calGini(dataSet) == 0:return dataSet[0][-1]# 属性值为空,只剩下类标签if len(dataSet[0]) == 1:return majorityCnt(classList)# 得到增益最大划分的属性、值bestFeat = chooseBestSplit(dataSet, labels)bestFeatLabel = labels[bestFeat]myTree = {bestFeatLabel: {}}  # 创建字典,即树的节点。# 生成子树的时候要将已遍历的属性删去。数值型不要删除。labelsCopy = labels[:]del (labelsCopy[bestFeat])uniqueVals = featureDic[bestFeatLabel]  # 最好的特征的类别列表for value in uniqueVals:  # 标称型的属性值有几种,就要几个子树。# Python中列表作为参数类型时,## 是按照引用传递的,要保证同一节点的子节点能有相同的参数。subLabels = labelsCopy[:]  # subLabels = 注意要用[:],不然还是引用subPrune = splitDataSet(pruneSet, bestFeat, value)subDataSet = splitDataSet(dataSet, bestFeat, value)if len(subDataSet) != 0:myTree[bestFeatLabel][value] = postPruning(subDataSet, subPrune, subLabels)else:# 计算D中样本最多的类myTree[bestFeatLabel][value] = majorityCnt(classList)# 后剪枝,如果到达叶子节点,尝试剪枝。# 计算未剪枝时,测试集的正确数numNoPrune = 0.0for value in uniqueVals:subDataSet = splitDataSet(dataSet, bestFeat, value)if len(subDataSet) != 0:subPrune = splitDataSet(pruneSet, bestFeat, value)numNoPrune += cntAccNums(subDataSet, subPrune)# 计算剪枝后,测试集正确数numPrune = cntAccNums(dataSet, pruneSet)# 比较决定是否剪枝, 如果剪枝后该节点上测试集的正确数变多了,则剪枝。if numNoPrune < numPrune:return majorityCnt(dataSet[:, -1])  # 直接返回节点上训练数据的多数类为节点类。return myTreedef main():dataSet, trainData, pruneData, labelList = getDataSet()# 用训练集训练一颗树并画图myTree = createTree(trainData, labelList)print(myTree)createPlot(myTree)# 画预剪枝树preTree = prePruning(trainData, pruneData, labelList)# createPlot(preTree)# 画后剪枝树postPTree = postPruning(trainData, pruneData, labelList)print(postPTree)# createPlot(postPTree)# 计算未剪枝的精度print(f"full tree's train accuracy = {calAccuracy(trainData, labelList, myTree)},"f"test accuracy = {calAccuracy(pruneData, labelList, myTree)}\n")# 计算预剪枝精度print(f"pre pruning tree's train accuracy = {calAccuracy(trainData, labelList, myTree)},"f"test accuracy = {calAccuracy(pruneData, labelList, preTree)}\n")# 计算后剪枝精度print(f"post pruning tree's train accuracy = {calAccuracy(trainData, labelList, myTree)},"f"test accuracy = {calAccuracy(pruneData, labelList, postPTree)}\n")if __name__ == '__main__':main()

http://chatgpt.dhexx.cn/article/spVCnE1J.shtml

相关文章

决策树之CART 算法(回归树,分类树)

CART 算法&#xff0c;英文全称叫做 Classification And Regression Tree&#xff0c;中文叫做分类回归树。 ID3 和 C4.5 算法可以生成二叉树或多叉树&#xff0c;而 CART 只支持二叉树。 同时 CART 决策树比较特殊&#xff0c;既可以作分类树&#xff0c;又可以作回归树。 …

决策树之CART(分类回归树)详解

决策树之CART&#xff08;分类回归树&#xff09;详解 主要内容 CART分类回归树简介CART分类回归树分裂属性的选择CART分类回归树的剪枝 1、CART分类回归树简介   CART分类回归树是一种典型的二叉决策树&#xff0c;可以做分类或者回归。如果待预测结果是离散型数据&#…

CART模型

(一)简介 1.CART(classification and regression tree)是应用广泛的决策树学习方法,既可以用于分类也可以用于回归; 2.CART假设决策树是二叉树,内部结点特征的取值为“是”和“否”,这样的决策树等价于递归地二分每个特征,将输入空间即特征空间划分为有限个单元,并…

免费前端网站页面模板

分享几个好的前端的免费模板的网站链接&#xff1a; 免费HTML5链接 网站展示&#xff1a; 网站模板链接2 模板网站3 网站展示&#xff1a; 精品插件以及模板 展示如下&#xff1a;

简洁实用的前端模板

好用的前端模板&#xff1a; 给兄弟萌推荐一个好用的前后端分离里面用到的前端的模板项目&#xff0c;使用Vue2.xElementUI写的。是一个非常可以值得借鉴的后台管理系统的前端模板。需要的同学可以下载之后&#xff0c;在此基础上修改&#xff0c;然后用到自己的项目中。 git…

web前端基础——背景图片

作用&#xff1a;设置背景图片大小 语法&#xff1a;background-size: 宽度 高度 取值&#xff1a; 取值场景数字px简单方便&#xff0c;常用百分比相对于当前盒子自身的宽高百分比contain包含&#xff0c;将背景图片等比例缩放&#xff0c;直到不会超出盒子的最大范围cover…

html+css+js实现的前端模板

代码功能 实现一个为用户提供能够快速制作主流表情包的网站。提供丰富的模板和在线自定义图片功能。可以对图片添加文字、水印和图片等功能。丰富的动画效果搭配颜值的前端模板&#xff0c;可以用来学习学习。 话不多说&#xff0c;上图片 有需要的可以去下载。 https://do…

前端案例:飞机大战( js+dom 操作,代码完整,附图片素材)

目录 一、案例效果 二、实现思路 三、完整代码详细注释 四、涉及要点 五、案例素材 一、案例效果 二、实现思路 创建游戏背景板&#xff1b;创建我方战机&#xff0c;鼠标进入游戏面板后其随鼠标轨迹运动&#xff1b; onmousemove创建子弹&#xff0c;让子弹周期性的在战…

博客前端模板

文章目录 序言效果展示菜单栏实现内容布局底部代码 序言 一直后端开发写接口&#xff0c;时间久了&#xff0c;把前端知识忘得一干二净了。最近公司项目不是很忙&#xff0c;想写一个博客练练手。模仿别人博客用bootstrap写了一个博客模板记录下。 效果展示 首页大屏效果&am…

前端设计类网站汇总

设计前端类网站汇总 一、素材类 1、图片 其实国内对图片版权保护这块的意识不是很够&#xff0c;在免费的素材库和收费素材库都能找到同一张图片&#xff0c;但作者署名却都不一样。所以小编现在基本不用国内这些图库网&#xff0c;跟大家推荐几个免费又没有版权纠纷的图库网站…

前端的你平时都在哪找免费的可商业用的图片素材?

周末好&#xff01;有段时间没有更新了&#xff0c;最近遇到找素材的苦恼&#xff0c;所以总结了一篇文章。前端中少不了与素材打交道&#xff0c;UI设计就更用说了&#xff0c;但能白嫖就白嫖&#xff0c;嘿嘿&#xff01;&#xff01;&#xff01;下面推荐一下有关能免费的可…

三个漂亮的网页登录页面源码及素材——可用于前端初学者练习HTMLCSS

注&#xff1a;这三个登录页面涉及到的图片素材可自行寻找&#xff0c;字体图标素材可以在阿里字体图标库获取&#xff08;https://www.iconfont.cn/home/index?spma313x.7781069.1998910419.2&#xff09;&#xff0c;如需原版素材可联系作者QQ&#xff08;3416252112&#x…

前端素材库网站集合——网站集合

UI矢量图库 1.摄图网 https://699pic.com/ https://699pic.com/tupian/tubiao.html?from215 图片素材图库 1.图库 https://picsum.photos/ 随机获取图片&#xff1a;&#xff08;每次刷新都可以获取一个新的图片&#xff09; http://picsum.photos/360/460?random1<d…

分享三个免费的前端模板网站

1、模板之家 网页模板,网站模板,DIVCSS模板,企业网站模板下载 http://www.cssmoban.com/ 2、站长之家 HTML5模板 HTML5模板免费下载 https://sc.chinaz.com/tag_moban/html5.html 3、jQuery之家 自由分享jQuery、html5、css3的插件库 http://www.htmleaf.com/

前端好用的素材网站分享

前端设计推荐的一些网站&#xff09; 1.[站酷](https://www.zcool.com.cn/)2.[ColorPalette](https://arco.design/palette/list)3.[unDraw](https://undraw.co/illustrations)4.[OUCH](https://icons8.cn/illustrations/style--pale)&#xff08;应该是叫这个吧&#xff09;5.…

前端常用素材网站整理

最近整理了网页收藏夹&#xff0c;将平时遇到与前端相关的素材网站归置归置 注意&#xff1a;有的下载模版需要充值 PPChart 让图表更简单 echarts图表案例 很全 啥图都有 http://www.ppchart.com/#/ ———————————————————————————————————…

Redis可视化管理工具推荐

AnotherRedisDesktopManager 码云地址&#xff1a;https://gitee.com/qishibo/AnotherRedisDesktopManager github地址&#xff1a;https://github.com/qishibo/AnotherRedisDesktopManager/ 很好用。推荐一下。

Redis 管理工具 RedisInsight

Redis 安装好并运行一段时间后&#xff0c;如何清晰的看到 Redis 占了多大内存&#xff0c;有多少个 KEY&#xff0c;所占的网络如何&#xff0c;这个在 RedisInsight 下就是一目了然了&#xff0c;特别方便。 下载也特别简单&#xff0c;到此网站下载你想要的版本就行。 ps&a…

Redis 管理工具 TreeNMS

今日&#xff0c;日月给大家介绍一款redis管理工具TreeNMS.下面我就详细给大家介绍一下treeNMS的安装及各项功能。 1、下载安装 下载地址&#xff1a;http://www.treesoft.cn/dms.html 下载到的是一个zip包&#xff0c;解压到指定的目录即可 windows下&#xff0c;直接双…

在window系统安装reids、并使用Redis可视化工具进行管理

下载地址 https://github.com/tporadowski/redis/releases 选择 Redis-x64-5.0.14.1.msi (微软的安装包 下载 安装好之后 打 开 一 个 cmd 窗 口 使 用 cd 命 令 切 换 目 录 到 安装目录下 D:\Program Files\Redis 执行命令 redis-server.exe redis.windows.conf 接下来…