ID3决策树算法实现

本文介绍了ID3决策树算法的理解与实现过程。通过阅读书籍和相关文章,作者逐步学习了算法,并分享了在代码理解上的挑战,强调了数据集处理及决策树构建的关键点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先对于ID3决策树我通过看书理解了其思想。
然后经过鱼佬的文章之后我学习了其算法实现。
感觉对代码的理解还是不够,很多地方还是没弄懂,要继续努力!
首先使用数据集

age,work,hourse,loan,class
青年,否,否,一般,否
青年,否,否,好,否
青年,是,否,好,是
青年,是,是,一般,是
青年,否,否,一般,否
中年,否,否,一般,否
中年,否,否,好,否
中年,是,是,好,是
中年,否,是,非常好,是
中年,否,是,非常好,是
老年,否,是,非常好,是
老年,否,是,好,是
老年,是,否,好,是
老年,是,否,非常好,是
老年,否,否,一般,否
处理
import pandas as pd
import numpy as np
import matplotlib as plt
from sklearn import preprocessing


dataset=pd.read_csv('/Users/soushigou/data.csv',encoding='gbk')
dataset.info()
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False

#得到变量列表,得到格式为list
cols=dataset.columns.tolist()
cols

#创建obj_vars列表,将描述型变量存入
obj_vars=[]
for col in cols:
    if dataset[col].dtype=="object":
        obj_vars.append(col)
print(obj_vars)

#将描述变量转化为数值型变量
#将转化为的数据附加到原始数据上
le=preprocessing.LabelEncoder()
for col in obj_vars:
    tran=le.fit_transform(dataset[col].tolist())
    tran_dataset=pd.DataFrame(tran,columns=['num_'+col])
    dataset=pd.concat([dataset,tran_dataset],axis=1)

注意:对于决策树来说描述型转换为数值型不是必须的

下面给出ID3决策树的python实现过程:

import pandas as pd
from math import log

def load(filename):
    '''
    input:文件
    output:DataFrame数据
    '''
    df=pd.read_csv(filename)
    return df

def calEnt(df):
    '''
    input:数据集
    output:熵
    description:计算给定数据集的熵
    '''
    #返回数据行数
    numEntries=df.shape[0]
    #字典,用于保存每个标签出现的次数
    labelCounts={}
    cols=df.columns.tolist()
    #获取标签
    classlabel=df[cols[-1]].tolist()
    #对每组特征向量进行统计
    for currentlabel in classlabel:
        if currentlabel not in labelCounts.keys():
            labelCounts[currentlabel]=1
        else:
            labelCounts[currentlabel]+=1
    Ent=0.0
    #计算熵
    for key in labelCounts:
        prob=labelCounts[key]/numEntries
        Ent-=prob*log(prob,2)

    return  Ent


def splitDatsSet(df,axis,value):
    '''
    :param df: 数据集
    :param axis: 所占列
    :param value: 选择值
    output:划分数据集
   description:按照给定特征划分数据集,选择所占列中等于选择值的项
    '''
    cols=df.columns.tolist()
    axisFeat=df[axis].tolist()
    #更新数据集
    retDataset=pd.concat([df[feaVec] for feaVec in cols if feaVec!=axis],axis=1)
    i=0
    #需要丢弃的行
    dropINdex=[]
    for feaVec in axisFeat:
        if feaVec!=value:
            dropINdex.apend(i)
            i+=1
        else:
            i+=1
    #划分数据集
    newDataset=retDataset.drop(dropINdex)
    return newDataset.reset_index(drop=True)

def chooseBestFeatureToSplit(df):
    '''
        input: 数据集
        output: 最优特征和信息增益
    '''
    # 获取特征数量
    numFeatures = len(df.columns) - 1
    # 计算熵
    Ent = calEnt(df)
    # 信息增益
    bestInfoGain = 0.0
    # 最优特征索引值
    bestFeature = -1
    cols = df.columns.tolist()
    # 遍历所有特征
    for i in range(numFeatures):
        # 获取第i个特征的所有不同的取值
        equalVals = set(df[cols[i]].tolist())
        # 经验条件熵
        newEnt = 0.0
        # 计算信息增益
        for value in equalVals:
            # 获取划分后的子集
            subDataset = splitDatsSet(df, cols[i], value)
            # 计算子集概率
            prob = subDataset.shape[0] / df.shape[0]
            # 根据公式计算条件熵
            newEnt += prob * calEnt(subDataset)
        infoGain = Ent - newEnt
        print(cols[i], infoGain)
        # 更新信息增益,找到最大的信息增益
        if infoGain > bestInfoGain:
            bestInfoGain = infoGain
            bestFeature = cols[i]
    return bestFeature, bestInfoGain



def majorityCnt(classList):
    '''
        input: 类别列表
        output: 子节点的分类
        description: 数据集已经处理了所有属性,但是类标签依然不是唯一的,
          采用多数判决的方法决定该子节点的分类
    '''
    classCount = {}
    # 统计classList中每个元素出现的次数
    for clas in classList:
        if clas not in classCount.keys():
            classCount[clas] = 0
        classCount[clas] += 1
    # 根据字典值降序排列
    sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reversed=True)
    return sortedClassCount[0][0]

def createTree(df, dropcol):
    '''
        input: 数据集和需删除特征
        output: 决策树
        description: 递归实现决策树构建
    '''
    # cols = df.columns.tolist()[:-1]
    # 取分类标签
    classList = df[df.columns.tolist()[-1]].tolist()

    # 若数据集中所有实例属于同一类,将Ck作为该节点的类标记
    if classList.count(classList[0]) == len(classList):
        return classList[0]

    # 若特征集为空集,将数据集中实例数最大的类Ck作为该节点的类标记
    if len(df[0:1]) == 0:
        return majorityCnt(classList)

    # 获取最优特征与信息增益
    bestFeature, bestInfoGain = chooseBestFeatureToSplit(df)

    print('特征集和类别:',df.columns.tolist())
    print('bestFeature:',bestFeature)
    # 根据最优特征的标签生成树
    myTree = {bestFeature:{}}
    # 得到最优特征的属性值
    featValues = df[bestFeature]
    # 去掉重复属性值
    uniqueVals = set(featValues)
    # 遍历创建决策树
    for value in uniqueVals:
        myTree[bestFeature][value] = createTree(splitDatsSet(df, bestFeature, value), bestFeature)
    return myTree

def main():
    filename = "data.csv"
    dataset = load(filename)
    dropCol = []
    myTree = createTree(dataset, dropCol)
    print(myTree)

if __name__ == '__main__':
    main()





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值