决策树递归调用时出错,python代码哪里出了问题?

1.描述问题:
一个决策树问题,运行代码出错。调试发现,递归调用返回第一个页结点时候出错,但是自己想不明白问题出在哪里。请大佬指导,非常感谢!
2.代码:

一、读取CSV文件并进行数据整理

1.读取csv文件

import pandas as pd
import numpy as np
import copy

df = pd.read_csv('d:/moni.csv', encoding='gb2312', header=0) # header=0意思第0行为标题;

2.计算香农熵

def calcShannonEnt(dataSet):
n = dataSet.shape[0] # 数据集总行数
iset = dataSet.iloc[:,-1].value_counts() # 标签的所有类别
p = iset/n # 每一类标签所占比
ent = (-p*np.log2(p)).sum() # 计算信息熵
return ent

3.定义特征属性(离散or连续)

data_disc_or_con = [0, 0, 0, 1, 1, 1, 1]

4选择最优的列进行切分(分离散和连续分别讨论)

def bestSplit(dataSet, tezshuxing):
baseEnt = calcShannonEnt(dataSet) # 计算原始熵
bestGain = 0 # 初始化信息增益
axis = -1 # 初始化最佳切分列,标签列
bestPartValuei = None # 最优划分点值,离散的话就是NONE,对于连续特征,该值在后面更新
bestInfoGain_local = 0 # 初始化最大信息增益等于0
for i in range(len(tezshuxing)): # 对特征的每一列进行循环
if tezshuxing[i] == 0: # 如果该列特征为离散型
ent_discrete = 0 # 初始化子节点的信息熵
levels = dataSet.iloc[:, i].value_counts().index # 提取出当前列的所有取值,对每个值计数,再提取计数表的索引
for j in levels: # 对当前列的每一个取值进行循环
childSet = dataSet[dataSet.iloc[:, i] == j] # 某一个子节点的dataframe
ent = calcShannonEnt(childSet) # 计算某一个子节点的信息熵
ent_discrete += (childSet.shape[0]/dataSet.shape[0])*ent # 计算当前列的信息熵
#print(f'第{i}列的信息熵为{ents}')
infoGain = baseEnt-ent_discrete # 计算当前列的信息增益

    else:
        sortedUniqueVals = list(set(dataSet.iloc[:, i]))  # 把数据集第i列先转化为集合,去掉重复;再转化为列表,为排序准备
        sortedUniqueVals.sort()                      #进行排序
        # listPartition = []                           #构建一个空列表

        for j in range(len(sortedUniqueVals) - 1):  # 计算划分点,划分点数量比特征值少一个
            partValue = (float(sortedUniqueVals[j]) + float(sortedUniqueVals[j + 1])) / 2
            # 对每个划分点,计算信息熵
            childSet1 = dataSet[dataSet.iloc[:, i] <= partValue]   # 提炼出小于等于划分点值的子集1
            childSet2 = dataSet[dataSet.iloc[:, i] > partValue]    # 提炼出大于划分点值的子集2
            ent1 = calcShannonEnt(childSet1)                       # 计算子集1熵值
            ent2 = calcShannonEnt(childSet2)                       # 计算子集2熵值
            # 计算该结点划分总熵值
            ents = ((childSet1.shape[0] / dataSet.shape[0]) * ent1) + ((childSet2.shape[0] / dataSet.shape[0]) * ent2)
            infoGain = baseEnt - ents
            if infoGain > bestInfoGain_local:   #如果这个结点计算出来的熵值比目前最小熵值还小
                bestInfoGain_local = infoGain
                # minEntropy_local = ents   #替换最小熵值(至此,知道以该特征划分可得到最小熵)
                #bestPartValuei = partValue   #这个划分点值等于最优划分点 (至此,知道该特征最小熵对应的划分点值)
        infoGain = bestInfoGain_local  # 计算当前列的信息增益

    if infoGain > bestGain:
        bestGain = infoGain  # 让离散或者连续特征对应的信息增益作为最大信息增益
        axis = i
        if data_disc_or_con[i] == 1:         # 当前最大增益对应的特征,如果是连续变量,将划分点的值赋予bestPartValuei
            bestPartValuei = partValue
return axis, bestPartValuei

(a,b) = bestSplit(df, data_disc_or_con)

print(a,b)

5切分数据包

5.1离散特征切分

def mySplit_dis(dataSet,axis,value):
col = dataSet.columns[axis]
redataSet = dataSet.loc[dataSet[col]==value,:].drop(col, axis=1)
return redataSet

5.2连续特征切分

def mySplit_con(dataSet, axis, value, LorR='L'):
col = dataSet.columns[axis]
if LorR == 'L':
redataSet = dataSet.loc[dataSet[col] <= value,:].drop(col,axis=1)
else:
redataSet = dataSet.loc[dataSet[col] >= value,:].drop(col,axis=1)
return redataSet

6定义一棵决策树

def createTree(dataSet, labels, labelProperty):
# featlist = list(dataSet.columns) # 提取出数据集所有的列
classlist = dataSet.iloc[:, -1].value_counts() # 获取最后一列类标签的计数表
# 判断最多标签数目是否等于数据集行数,或者数据集是否只有一列
if classlist[1]==dataSet.shape[0] or dataSet.shape[1] == 1:
return classlist.index[0] # 如果是,返回类标签
bestFeat, bestPartValue = bestSplit(dataSet, labelProperty) # 确定出当前最佳切分列的索引
if bestFeat == -1:
return classlist.index[0] # classlist自动会把不同标签按照出现次序进行排序显示,index[0]显示最多标签
if labelProperty[bestFeat] == 0: # 对于离散变量
bestfeatlabel = labels[bestFeat] # 获取该索引对应的特征
myTree = {bestfeatlabel: {}} # 采用字典嵌套的方式存储树信息
labelsNew = copy.copy(labels)
labelPropertyNew = copy.copy(labelProperty)
del labelsNew[bestFeat] # 删除当前特征
del labelPropertyNew[bestFeat] # 删除特征值对应属性
featValues = set(dataSet.iloc[:, bestFeat]) # 提取最佳切分列所有属性值
for value in featValues: # 对每一个属性值递归建树
sublabels = labelsNew[:]
sublabelsProperty = labelPropertyNew[:]
myTree[bestfeatlabel][value] = createTree(mySplit_dis(dataSet, bestFeat, value),sublabels, sublabelsProperty)
else:
bestfeatlabel = labels[bestFeat] + '<' + str(bestPartValue) # 获取该索引对应的特征
myTree = {bestfeatlabel: {}} # 采用字典嵌套的方式存储树信息
sublabels = labels[:]
sublabelsProperty = labelProperty[:]
valueLeft = '是'
myTree[bestfeatlabel][valueLeft] = createTree(mySplit_con(dataSet, bestFeat, bestPartValue, 'L'), sublabels,sublabelsProperty)
# 构建右子树
valueRight = '否'
myTree[bestfeatlabel][valueRight] = createTree(mySplit_con(dataSet, bestFeat, bestPartValue, 'R'),sublabels,sublabelsProperty)

return myTree

labels = ['degree', 'job', 'sex', 'age', 'years of ex', 'maxWendingqi', 'last_year']
mytree = createTree(df,labels, data_disc_or_con)

https://blog.csdn.net/zhaihao1996/article/details/100929131