Python实现决策树2(CART分类树及CART回归树)

article/2025/10/31 0:33:35

接上篇
    CART算法的全称是Classification And Regression Tree,采用的是Gini指数(选Gini指数最小的特征s)作为分裂标准,同时它也是包含后剪枝操作。ID3算法和C4.5算法虽然在对训练样本集的学习中可以尽可能多地挖掘信息,但其生成的决策树分支较大,规模较大。为了简化决策树的规模,提高生成决策树的效率,就出现了根据GINI系数来选择测试属性的决策树算法CART。

    CART分类与回归树本质上是一样的,构建过程都是逐步分割特征空间,预测过程都是从根节点开始一层一层的判断直到叶节点给出预测结果。只不过分类树给出离散值,而回归树给出连续值(通常是叶节点包含样本的均值),另外分类树基于Gini指数选取分割点,而回归树基于平方误差选取分割点。

6.CART分类树

基尼指数,分类问题中,假设有K个类,样本点属于第k类的概率为 p k p_{k} pk,则概率分布的基尼指数定义为:
G i n i ( p ) = 1 − ∑ k = 1 K p k ( 1 − p k ) = 1 − ∑ k = 1 K p k 2 Gini(p)=1-\sum_{k=1}^{K}p_k(1-p_k)=1-\sum_{k=1}^{K}p_k^2 Gini(p)=1k=1Kpk(1pk)=1k=1Kpk2

如果样本集合D根据特征A是否取某一肯值 a a a被分割成 D 1 D_1 D1 D 2 D_2 D2两部分,即:
D 1 = ( x , y ) ∈ D ∣ A ( x ) = a , D 2 = D − D 1 D_1={(x,y)∈D|A(x)=a} , D_2=D-D_1 D1=(x,y)DA(x)=a,D2=DD1

则在特征A的条件下,集合D的基尼指数定义为:
G i n i ( D , A ) = ∣ D 1 ∣ ∣ D ∣ G i n i ( D 1 ) + ∣ D 2 ∣ ∣ D ∣ G i n i ( D 2 ) Gini(D,A)=\frac{|D_1|}{|D|}Gini(D_1) + \frac{|D_2|}{|D|}Gini(D_2) Gini(D,A)=DD1Gini(D1)+DD2Gini(D2)
基尼指数 G i n i ( D ) Gini(D) Gini(D)表示D的不确定性,基尼指数 G i n i ( D , A ) Gini(D,A) Gini(D,A)表示 A = a A=a A=a分割后集合D的不确定性,基尼指数值越大,样本集合的不确定性就越大,与熵类似。

CART分类树算法逻辑,《统计学习方法》李航,P70-71页:在这里插入图片描述
在这里插入图片描述

按传入数据最后一列y值求gini指数

# 计算传入数据的Gini指数
def calcGini(dataSet):#dataSet=dataSet[list(dataSet[:,0]=='青年')]# 获得y中分类标签的唯一值y_lables = np.unique(dataSet[: , -1])y_counts=len(dataSet) # y总数据条数y_p={}             # y中每一个分类的概率,字典初始化为空,y分类数是不定的,按字典存储更方便取值gini=1.0for y_lable in y_lables:y_p[y_lable]=len(dataSet[dataSet[:, -1]==y_lable])/y_counts  # y中每一个分类的概率(其实就是频率)gini-=y_p[y_lable]**2return gini

切分数据,每一列x找一个最优的特征进行划分

#划分数据集
def splitDataSet(dataSet, i, value,types=1):#dataSet[list(dataSet[:,0]!='青年')]if types==1: # 使用此列特征中的value进行划分数据subDataSet=dataSet[list(dataSet[:,i]==value)]  # 按照数据x第i列==value即可判断,不需要像《机器学习实战》书里写的那么复杂subDataSet = np.array(subDataSet)           # 强制转换为array类型elif types==2: # 使用此列特征中的不等于value的进行划分数据subDataSet=dataSet[list(dataSet[:,i]!=value)]  # 按照数据x第i列==value即可判断,不需要像《机器学习实战》书里写的那么复杂subDataSet = np.array(subDataSet)           # 强制转换为array类型return subDataSet ,len(subDataSet)

遍历所有x特征列中的所有特征,寻找最优划分特征

# 计算Gini指数,选择最好的特征划分数据集,即返回最佳特征下标及传入数据集各列的Gini指数
def chooseBestFeature(dataSet,types='Gini'):numTotal=dataSet.shape[0]              # 记录本数据集总条数numFeatures = len(dataSet[0]) - 1      # 最后一列为y,计算x特征列数bestFeature = -1                       # 初始化参数,记录最优特征列i,下标从0开始columnFeaGini={}                       # 初始化参数,记录每一列x的每一种特征的基尼 Gini(D,A)for i in range(numFeatures):           # 遍历所有x特征列# i=2prob = {}                          # 按x列计算各个分类的概率featList = list(dataSet[:,i])      # 取这一列x中所有数据,转换为list类型prob=dict(Counter(featList))       # 使用Counter函数计算这一列x各特征数量for value in prob.keys():          # 循环这一列的特征,计算H(D|A)# value='是'feaGini = 0.0bestFlag = 1.00001  # 对某一列x中,会出现x=是,y=是的特殊情况,这种情况下按“是”、“否”切分数据得到的Gini都一样,设置此参数将所有特征都乘以一个比1大一点点的值,但按某特征划分Gini为0时,设置为1subDataSet1,sublen1 = splitDataSet(dataSet, i, value, 1)  # 获取切分后的数据subDataSet2,sublen2 = splitDataSet(dataSet, i, value, 2)if (sublen1/numTotal) * calcGini(subDataSet1)==0: # 判断按此特征划分Gini值是否为0(全部为一类)bestFlag = 1 feaGini += (sublen1/numTotal) * calcGini(subDataSet1) + (sublen2/numTotal) * calcGini(subDataSet2)columnFeaGini['%d_%s'%(i,value)]=feaGini*bestFlagbestFeature=min(columnFeaGini,key=columnFeaGini.get) # 找到最小的Gini指数益对应的数据列return bestFeature,columnFeaGini

CART分类树创建主函数,递归调用产生整颗决策树

def createTree(dataSet,features,types='Gini'):"""输入:训练数据集D,特征集A,阈值ε输出:决策树T"""y_lables = np.unique(dataSet[: , -1])#1、如果数据集D中的所有实例都属于同一类label(Ck),则T为单节点树,并将类label(Ck)作为该结点的类标记,返回Tif len(set(y_lables)) == 1:return y_lables[0]#2、若特征集A=空,则T为单节点,并将数据集D中实例树最大的类label(Ck)作为该节点的类标记,返回Tif len(dataSet[0]) == 1:labelCount = {}labelCount=dict(Counter(y_lables))return max(labelCount,key=labelCount.get)#3、否则,按CART算法就计算特征集A中各特征对数据集D的Gini,选择Gini指数最小的特征bestFeature(Ag)进行划分bestFeature,columnFeaGini=chooseBestFeature(dataSet,types) bestFeatureLable = features[int(bestFeature.split('_')[0])]    #最佳特征decisionTree = {bestFeatureLable:{}}        #构建树,以Gini指数最小的特征bestFeature为子节点del(features[int(bestFeature.split('_')[0])])                  #该特征已最为子节点使用,则删除,以便接下来继续构建子树#使用beatFeature进行划分,划分产生2各节点,成树T,返回Ty_lables_split=dataSet[list(dataSet[:,int(bestFeature.split('_')[0])]==bestFeature.split('_')[1])][:,-1] # 获取按此划分后y数据列表y_lables_grp=dict(Counter(y_lables_split)) # 统计最优划分应该属于哪个i叶子节点“是”、“否”y_leaf=max(y_lables_grp,key=y_lables_grp.get) # 获得划分后出现概率最大的y分类decisionTree[bestFeatureLable][bestFeature.split('_')[1]]= y_leaf # 设定左枝叶子值#4、删除此最优划分数据x列,使用其他x列数据,递归地调用步1-3,得到子树Ti,返回TidataSetNew= np.delete(dataSet,int(bestFeature.split('_')[0]),axis=1) # 删除此最优划分x列,使用剩余的x列进行数据划分subFeatures = features[:]# 判断右枝类型,划分后的左右枝“是”、“否”是不一定的,所以这里进行判断y1=y_lables[0] # CART树y只能有2个分类y2=y_lables[1] if y_leaf==y1:decisionTree[bestFeatureLable][y2]= {}decisionTree[bestFeatureLable][y2] = createTree(dataSetNew, subFeatures,types)elif y_leaf==y2:decisionTree[bestFeatureLable][y1]= {}decisionTree[bestFeatureLable][y1] = createTree(dataSetNew, subFeatures,types)return decisionTree

cart决策树结果验证,计算结果与《统计学习方法》李航,P71页一致。
在这里插入图片描述

cart决策树及画图结果:
在这里插入图片描述

7.CART回归树

CART回归树样本空间细分成若干子空间,子空间内样本的输出y(连续值)的均值即为该子空间内的预测值。故对于输入X为一维时,预测结果可表示为阶梯函数。
评估方式采用平方误差:yi 属于某个数据集,c为该数据上输出向量y的均值。
e r r = ∑ ( y i − c ) err=\sum(y_i-c) err=(yic)

CART回归树算法逻辑,《统计学习方法》李航,P69页:
在这里插入图片描述

最小二乘损失

def err(dataSet):#return sum((dataSet[:,-1]- dataSet[:,-1].mean())**2) # 最原始的写法return np.var(dataSet[:,-1])*dataSet.shape[0]  #均方差*数据总条数

划分数据集,按出入的数据列fea,数据值value将数据划分为两部分

def splitDataSet(dataSet, fea, value):dataSet1=dataSet[dataSet[:,fea]<=value]dataSet2=dataSet[dataSet[:,fea]>value]return dataSet1,dataSet2

#选择最好的特征划分数据集,min_sample每次划分后每部分最少的数据条数,epsilon误差下降阈值,值越小划分的决策树越深

def chooseBestFeature(dataSet,min_sample=4,epsilon=0.5):features=dataSet.shape[1]-1   # x特征列数量sErr=err(dataSet) # 整个数据集的损失minErr=np.infbestColumn = 0 # 划分最优列bestValue = 0  # 划分最优的值nowErr=0       # 当前平方误差if len(np.unique(dataSet[:,-1].T.tolist())) == 1: # 数据全是一类的情况下 返回return None, np.mean(dataSet[:,-1])for fea in range(0,features): # 按x特征列循环for row in range(0,dataSet.shape[0]): # 遍历每行数据,寻找最优划分dataSet1,dataSet2=splitDataSet(dataSet, fea,dataSet[row,fea]) # 获得切分后的数据if len(dataSet1) < min_sample or len(dataSet2) < min_sample:  # 按行遍历时总会有一些划分得到的集合不满足最小数据条数约束,跳过此类划分continuenowErr=err(dataSet1)+err(dataSet2) # 计算当前划分的平方误差#print('fea:',fea,'row:',row,'datavalue',dataSet[row,fea],'nowErr',nowErr)if nowErr<minErr: # 判断获得最优切分值minErr=nowErrbestColumn=feabestValue=dataSet[row,fea]#print('fea',fea,'minErr',minErr,'bestColumn',bestColumn,'bestValue',bestValue)if (sErr - minErr) < epsilon: # 当前误差下降较小时,返回return None, np.mean(dataSet[:,-1])# 当前最优划分集合dataSet1,dataSet2=splitDataSet(dataSet, bestColumn,bestValue)if len(dataSet1) < min_sample or len(dataSet2) < min_sample: # 如果划分的数据集很小,返回return None, np.mean(dataSet[:,-1])return bestColumn,bestValue

CART回归树控制主函数,递归调用产生整颗树

def createTree(dataSet):"""输入:训练数据集D,特征集A,阈值ε输出:决策树T"""bestColumn,bestValue=chooseBestFeature(dataSet)if bestColumn == None:  # 所有列均遍历完毕,返回return bestValueretTree = {}  # 决策树 retTree['spCol'] = bestColumn # 最优分割列retTree['spVal'] = bestValue  # 最优分割值lSet, rSet = splitDataSet(dataSet, bestColumn,bestValue) # 按当前最优分割列级值划分为左右2枝retTree['left'] = createTree(lSet)  # 迭代继续划分左枝retTree['right'] = createTree(rSet) # 迭代继续划分右枝return retTree

CART回归树输出结果:
在这里插入图片描述

CART分类树完整代码:

# -*- coding: utf-8 -*-
"""@Time    : 2018/11/16 09:58@Author  : hanzi5@Email   : hanzi5@yeah.net@File    : cart_classification.py@Software: PyCharm
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
from collections import Countermatplotlib.rcParams['font.family']='SimHei'  # 用来正常显示中文
plt.rcParams['axes.unicode_minus']=False  # 用来正常显示负号decisionNode = dict(boxstyle="sawtooth", fc="0.8")
leafNode = dict(boxstyle="round4", fc="0.8")
arrow_args = dict(arrowstyle="<-")# 计算传入数据的Gini指数
def calcGini(dataSet):#dataSet=dataSet[list(dataSet[:,0]=='青年')]# 获得y中分类标签的唯一值y_lables = np.unique(dataSet[: , -1])y_counts=len(dataSet) # y总数据条数y_p={}             # y中每一个分类的概率,字典初始化为空,y分类数是不定的,按字典存储更方便取值gini=1.0for y_lable in y_lables:y_p[y_lable]=len(dataSet[dataSet[:, -1]==y_lable])/y_counts  # y中每一个分类的概率(其实就是频率)gini-=y_p[y_lable]**2return gini# 计算Gini指数的另一种写法
def getGini(dataSet):# 计算基尼指数c = Counter(dataSet[:,-1])ret=1 - sum([(val / dataSet[:,-1].shape[0]) ** 2 for val in c.values()])return ret#划分数据集
def splitDataSet(dataSet, i, value,types=1):#dataSet[list(dataSet[:,0]!='青年')]if types==1: # 使用此列特征中的value进行划分数据subDataSet=dataSet[list(dataSet[:,i]==value)]  # 按照数据x第i列==value即可判断,不需要像《机器学习实战》书里写的那么复杂subDataSet = np.array(subDataSet)           # 强制转换为array类型elif types==2: # 使用此列特征中的不等于value的进行划分数据subDataSet=dataSet[list(dataSet[:,i]!=value)]  # 按照数据x第i列==value即可判断,不需要像《机器学习实战》书里写的那么复杂subDataSet = np.array(subDataSet)           # 强制转换为array类型return subDataSet ,len(subDataSet)# 计算Gini指数,选择最好的特征划分数据集,即返回最佳特征下标及传入数据集各列的Gini指数
def chooseBestFeature(dataSet,types='Gini'):numTotal=dataSet.shape[0]              # 记录本数据集总条数numFeatures = len(dataSet[0]) - 1      # 最后一列为y,计算x特征列数bestFeature = -1                       # 初始化参数,记录最优特征列i,下标从0开始columnFeaGini={}                       # 初始化参数,记录每一列x的每一种特征的基尼 Gini(D,A)for i in range(numFeatures):           # 遍历所有x特征列# i=2prob = {}                          # 按x列计算各个分类的概率featList = list(dataSet[:,i])      # 取这一列x中所有数据,转换为list类型prob=dict(Counter(featList))       # 使用Counter函数计算这一列x各特征数量for value in prob.keys():          # 循环这一列的特征,计算H(D|A)# value='是'feaGini = 0.0bestFlag = 1.00001  # 对某一列x中,会出现x=是,y=是的特殊情况,这种情况下按“是”、“否”切分数据得到的Gini都一样,设置此参数将所有特征都乘以一个比1大一点点的值,但按某特征划分Gini为0时,设置为1subDataSet1,sublen1 = splitDataSet(dataSet, i, value, 1)  # 获取切分后的数据subDataSet2,sublen2 = splitDataSet(dataSet, i, value, 2)if (sublen1/numTotal) * calcGini(subDataSet1)==0: # 判断按此特征划分Gini值是否为0(全部为一类)bestFlag = 1 feaGini += (sublen1/numTotal) * calcGini(subDataSet1) + (sublen2/numTotal) * calcGini(subDataSet2)columnFeaGini['%d_%s'%(i,value)]=feaGini*bestFlagbestFeature=min(columnFeaGini,key=columnFeaGini.get) # 找到最小的Gini指数益对应的数据列return bestFeature,columnFeaGinidef createTree(dataSet,features,types='Gini'):"""输入:训练数据集D,特征集A,阈值ε输出:决策树T"""y_lables = np.unique(dataSet[: , -1])#1、如果数据集D中的所有实例都属于同一类label(Ck),则T为单节点树,并将类label(Ck)作为该结点的类标记,返回Tif len(set(y_lables)) == 1:return y_lables[0]#2、若特征集A=空,则T为单节点,并将数据集D中实例树最大的类label(Ck)作为该节点的类标记,返回Tif len(dataSet[0]) == 1:labelCount = {}labelCount=dict(Counter(y_lables))return max(labelCount,key=labelCount.get)#3、否则,按CART算法就计算特征集A中各特征对数据集D的Gini,选择Gini指数最小的特征bestFeature(Ag)进行划分bestFeature,columnFeaGini=chooseBestFeature(dataSet,types) bestFeatureLable = features[int(bestFeature.split('_')[0])]    #最佳特征decisionTree = {bestFeatureLable:{}}        #构建树,以Gini指数最小的特征bestFeature为子节点del(features[int(bestFeature.split('_')[0])])                  #该特征已最为子节点使用,则删除,以便接下来继续构建子树#使用beatFeature进行划分,划分产生2各节点,成树T,返回Ty_lables_split=dataSet[list(dataSet[:,int(bestFeature.split('_')[0])]==bestFeature.split('_')[1])][:,-1] # 获取按此划分后y数据列表y_lables_grp=dict(Counter(y_lables_split)) # 统计最优划分应该属于哪个i叶子节点“是”、“否”y_leaf=max(y_lables_grp,key=y_lables_grp.get) # 获得划分后出现概率最大的y分类decisionTree[bestFeatureLable][bestFeature.split('_')[1]]= y_leaf # 设定左枝叶子值#4、删除此最优划分数据x列,使用其他x列数据,递归地调用步1-3,得到子树Ti,返回TidataSetNew= np.delete(dataSet,int(bestFeature.split('_')[0]),axis=1) # 删除此最优划分x列,使用剩余的x列进行数据划分subFeatures = features[:]# 判断右枝类型,划分后的左右枝“是”、“否”是不一定的,所以这里进行判断y1=y_lables[0] # CART树y只能有2个分类y2=y_lables[1] if y_leaf==y1:decisionTree[bestFeatureLable][y2]= {}decisionTree[bestFeatureLable][y2] = createTree(dataSetNew, subFeatures,types)elif y_leaf==y2:decisionTree[bestFeatureLable][y1]= {}decisionTree[bestFeatureLable][y1] = createTree(dataSetNew, subFeatures,types)return decisionTree####以下是用来画图的完全复制的《机器学习实战》第三章的内容,不感兴趣的可以略过#############################################
def getNumLeafs(myTree):numLeafs = 0firstStr = list(myTree.keys())[0]secondDict = myTree[firstStr]for key in secondDict.keys():if type(secondDict[key]).__name__=='dict':#test to see if the nodes are dictonaires, if not they are leaf nodesnumLeafs += getNumLeafs(secondDict[key])else:   numLeafs +=1return numLeafsdef getTreeDepth(myTree):maxDepth = 0firstStr = list(myTree.keys())[0]#myTree.keys()[0]secondDict = myTree[firstStr]for key in secondDict.keys():if type(secondDict[key]).__name__=='dict':#test to see if the nodes are dictonaires, if not they are leaf nodesthisDepth = 1 + getTreeDepth(secondDict[key])else:   thisDepth = 1if thisDepth > maxDepth: maxDepth = thisDepthreturn maxDepthdef 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 )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, va="center", ha="center", rotation=30)def plotTree(myTree, parentPt, nodeTxt):#if the first key tells you what feat was split onnumLeafs = getNumLeafs(myTree)  #this determines the x width of this tree#depth = getTreeDepth(myTree)firstStr = list(myTree.keys())[0]#myTree.keys()[0]     #the text label for this node should be thiscntrPt = (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':#test to see if the nodes are dictonaires, if not they are leaf nodes   plotTree(secondDict[key],cntrPt,str(key))        #recursionelse:   #it's a leaf node print the leaf nodeplotTree.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.totalD
#if you do get a dictonary you know it's a tree, and the first element will be another dictdef createPlot(myTree):fig = plt.figure(1, facecolor='white')fig.clf()axprops = dict(xticks=[], yticks=[])createPlot.ax1 = plt.subplot(111, frameon=False, **axprops)    #no ticks#createPlot.ax1 = plt.subplot(111, frameon=False) #ticks for demo puropses plotTree.totalW = float(getNumLeafs(myTree))plotTree.totalD = float(getTreeDepth(myTree))plotTree.xOff = -0.5/plotTree.totalW; plotTree.yOff = 1.0;plotTree(myTree, (0.5,1.0), '')plt.show()
####画图结束,不感兴趣的可以略过#############################################if __name__ == "__main__":  #读入数据,《统计学习方法》李航,P59,表5.1df_data=pd.read_csv('D:/python_data/loan_application.csv')features = list(df_data.columns[1:-1]) # x的表头dataSet=np.array(df_data.values[:,1:]) # 数据处理为numpy.array类型,其实pandas.Dataframe类型更方便计算# 结果验证,计算结果与《统计学习方法》李航,P71页一致。bestFeature,columnFeaGini=chooseBestFeature(dataSet,'Gini')print('\nbestFeature:',bestFeature,'\nGini(D,A):',columnFeaGini)dt_Gini = createTree(dataSet, features,'Gini')   #建立决策树,CART分类树print( 'CART分类树:\n',dt_Gini)# 画出决策树createPlot(dt_Gini)

CART回归树完整代码:

# -*- coding: utf-8 -*-
"""@Time    : 2018/11/19 14:45@Author  : hanzi5@Email   : hanzi5@yeah.net@File    : cart_reg.py@Software: PyCharm
"""import numpy as np
import pandas as pd
import matplotlib.pyplot as plt# 最小二乘损失
def err(dataSet):#return sum((dataSet[:,-1]- dataSet[:,-1].mean())**2) # 最原始的写法return np.var(dataSet[:,-1])*dataSet.shape[0]  #均方差*数据总条数#划分数据集,按出入的数据列fea,数据值value将数据划分为两部分
def splitDataSet(dataSet, fea, value):dataSet1=dataSet[dataSet[:,fea]<=value]dataSet2=dataSet[dataSet[:,fea]>value]return dataSet1,dataSet2# 选择最好的特征划分数据集,min_sample每次划分后每部分最少的数据条数,epsilon误差下降阈值,值越小划分的决策树越深
def chooseBestFeature(dataSet,min_sample=4,epsilon=0.5):features=dataSet.shape[1]-1   # x特征列数量sErr=err(dataSet) # 整个数据集的损失minErr=np.infbestColumn = 0 # 划分最优列bestValue = 0  # 划分最优的值nowErr=0       # 当前平方误差if len(np.unique(dataSet[:,-1].T.tolist())) == 1: # 数据全是一类的情况下 返回return None, np.mean(dataSet[:,-1])for fea in range(0,features): # 按x特征列循环for row in range(0,dataSet.shape[0]): # 遍历每行数据,寻找最优划分dataSet1,dataSet2=splitDataSet(dataSet, fea,dataSet[row,fea]) # 获得切分后的数据if len(dataSet1) < min_sample or len(dataSet2) < min_sample:  # 按行遍历时总会有一些划分得到的集合不满足最小数据条数约束,跳过此类划分continuenowErr=err(dataSet1)+err(dataSet2) # 计算当前划分的平方误差#print('fea:',fea,'row:',row,'datavalue',dataSet[row,fea],'nowErr',nowErr)if nowErr<minErr: # 判断获得最优切分值minErr=nowErrbestColumn=feabestValue=dataSet[row,fea]#print('fea',fea,'minErr',minErr,'bestColumn',bestColumn,'bestValue',bestValue)if (sErr - minErr) < epsilon: # 当前误差下降较小时,返回return None, np.mean(dataSet[:,-1])# 当前最优划分集合dataSet1,dataSet2=splitDataSet(dataSet, bestColumn,bestValue)if len(dataSet1) < min_sample or len(dataSet2) < min_sample: # 如果划分的数据集很小,返回return None, np.mean(dataSet[:,-1])return bestColumn,bestValuedef createTree(dataSet):"""输入:训练数据集D,特征集A,阈值ε输出:决策树T"""bestColumn,bestValue=chooseBestFeature(dataSet)if bestColumn == None:  # 所有列均遍历完毕,返回return bestValueretTree = {}  # 决策树 retTree['spCol'] = bestColumn # 最优分割列retTree['spVal'] = bestValue  # 最优分割值lSet, rSet = splitDataSet(dataSet, bestColumn,bestValue) # 按当前最优分割列级值划分为左右2枝retTree['left'] = createTree(lSet)  # 迭代继续划分左枝retTree['right'] = createTree(rSet) # 迭代继续划分右枝return retTreeif __name__ == '__main__':# 使用sin函数随机产生x,y数据X_data_raw = np.linspace(-3, 3, 50)np.random.shuffle(X_data_raw)  # 随机打乱数据y_data = np.sin(X_data_raw)    # 产生数据yx = np.transpose([X_data_raw]) # 将x进行转换y = y_data + 0.1 * np.random.randn(y_data.shape[0]) # 产生数据y,增加随机噪声dataSet=np.column_stack((x,y.reshape((-1,1))))      # 将x与y进行合并#    data=pd.read_table('D:/python_data/ex0.txt',header=None)
#    dataSet=data.valuesmytree=createTree(dataSet) print('mytree\n',mytree)

注意,以上实现的CART分类树与CART回归树均没有进行减枝操作。

参考资料:
1、Machine-Learning-With-Python
2、《机器学习实战》Peter Harrington著
3、《机器学习》西瓜书,周志华著
4、 斯坦福大学公开课 :机器学习课程
5、机器学习视频,邹博
6、《统计学习方法》李航
7、《机器学习实战》基于信息论的三种决策树算法(ID3,C4.5,CART)
8、分类回归——CART分类与回归以及Python实现


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

相关文章

树模型之三种常见的决策树:CART,…

树模型&#xff08;又称决策树或者树结构模型&#xff09;&#xff1a;基本思想和方差分析中的变异分解极为相似。 目的&#xff08;基本原则&#xff09;&#xff1a;将总研究样本通过某些牲&#xff08;自变量取值&#xff09;分成数个相对同质的子样本。每一子样本因变量的取…

决策树CART

分类回归树(CART,Classification And Regression Tree)也属于一种决策树&#xff0c;上回文我们介绍了基于ID3算法的决策树。作为上篇&#xff0c;这里只介绍CART是怎样用于分类的。 分类回归树是一棵二叉树&#xff0c;且每个非叶子节点都有两个孩子&#xff0c;所以对于第一棵…

决策树CART算法原理详解

大家好&#xff0c;今天用一个简单的例子来给大家介绍一下决策树中的CART算法。 CART分类树 CART分类树适用于预测结果为离散型数据的情况下&#xff0c;主要是计算每一组特征的Gini系数增益来确定决策树划分的优先规则&#xff0c;主要是采用一种二分方法&#xff0c;当一列…

决策树—ID3、C4.5、CART

目录 一、决策树模型与学习 1、决策树模型 2、决策树学习 二、特征选择 1、信息增益 2、信息增益率 三、决策树的生成 1、ID3算法 2、C4.5算法 3、CART算法 四、决策树停止分裂的条件 五、连续值和损失值处理 决策树&#xff08;decision tree&#xff09;是一…

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

文章目录 CART决策树----基尼指数划分一.决策树算法的构建二.划分选择——基尼指数三.剪枝处理1.预剪枝2.后剪枝 四.算法代码 CART决策树----基尼指数划分 一.决策树算法的构建 一般的&#xff0c;一棵决策树包含一个根节点&#xff0c;若干个内部结点和若干个叶结点&#xff…

决策树之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.…