【Python】ID3算法的实现

ID3实现

首先定义一个ID3DTree类来封装算法

# coding:utf-8
#Python3.7.2
from numpy import *
import math
import copy
import _pickle as pickle


class ID3DTree(object):
    def __init__(self):
        self.tree = {}
        self.dataSet = []
        self.labels = []

数据导入函数

    def loadDataSet(self, path, labels):
        recordlist = []
        fp = open(path, 'rb')
        content = fp.read()
        fp.close()
        rowlist = content.splitlines()
        recordlist = [row.split('\t') for row in rowlist if row.strip()]
        self.dataSet = recordlist
        self.labels = labels

执行决策树函数

    def train(self):
        labels = copy.deepcopy(self.labels)
        self.tree = self.buildTree(self.dataSet, labels)

决策树主方法

构建决策树:创建决策树主程序

    def buildTree(self, dataSet, lebels):
        cateList = [data[-1] for data in dataSet]
        if cateList.count(cateList[0]) == len(cateList):
            return cateList[0]
        if len(dataSet[0]) == 1:
            return self.maxCate(cateList)
        bestFeat = self.getBestFeat(dataSet)
        bestFeatLabel = labels[bestFeat]
        tree = {bestFeatLabel: {}}
        del(labels[bestFeat])
        uniqueVals = set([data[bestFeat] for data in dataSet])
        for value in uniqueVals:
            subLabels = labels[:]
            splitDataset = self.splitDataset(dataSet, bestFeat, value)
            subTree = self.buildTree(splitDataset, subLabels)
            tree[bestFeatLabel][value] = subTree
        return tree

计算出现次数最多的类别标签

    def maxCate(self, cateList):
        items = dict([(cateList.count(i), i) for i in cateList])
        return items[max(items.keys())]

计算最优特征

    def getBestFeat(self, dataSet):
        numFeatures = len(dataSet[0])-1
        baseEntropy = self.computeEntropy(dataSet)
        bestInfoGain = 0.0
        bestFeature = -1
        for i in range(numFeatures):
            uniqueVals = set([data[i] for data in dataSet])
            newEntropy = 0.0
            for value in uniqueVals:
                subDataSet = self.splitDataset(dataSet, i, value)
                prob = len(subDataSet)/float(len(dataSet))
                newEntropy += prob*self.computeEntropy(subDataSet)
            infoGain = baseEntropy-newEntropy
            if(infoGain > bestInfoGain):
                bestInfoGain = infoGain
                bestFeature = i
        return bestFeature

计算信息熵

    def computeEntropy(self, dataSet):
        datalen = float(len(dataSet))
        cateList = [data[-1] for data in dataSet]
        items = dict([(i, cateList.count(i)) for i in cateList])
        infoEntropy = 0.0
        for key in items:
            prob = float(items[key])/datalen
            infoEntropy -= prob*math.log(prob, 2)
        return infoEntropy

划分数据集

def splitDataset(self, dataSet, axis, value):
    rtnList = []
    for featVec in dataSet:
        if featVec[axis] == value:
            rFeatVec = featVec[:axis]
            rFeatVec.extend(featVec[axis+1:])
            rtnList.append(rFeatVec)
    return rtnList

训练决策树

数据集下载:
链接: 数据集下载
提取码:1tgp

dtree = ID3DTree()
dtree.loadDataSet("数据集.dat", ["age", "revenue", "student", "credit"])
dtree.train()
print(dtree.tree)

执行结果:

{'age': {'1': 'yes', '0': {'student': {'1': 'yes', '0': 'no'}}, '2': {'credit': {'1': 'no', '0': 'yes'}}}}

输出的结果是一个数据字典,我们将此字典转换为树状的形式
在这里插入图片描述

可以看到图中创建的决策树结构与json相同,说明算法正确。

持久化决策树

ID3类也提供了专门的方法用于保存决策树到文件,并可从文件读取决策树到内存。

def storeTree(self,inputTree,filename):     # 存储树到文件
        fw = open(filename,'w')
        pickle.dump(inputTree,fw)
        fw.close()
           
  def grabTree(self,filename):                                  # 从文件抓取树
        fr = open(filename)
        return pickle.load(fr)

执行代码如下。

dtree.storeTree(dtree.tree,"data.tree")
  mytree = dtree.grabTree("data.tree")
  print mytre

执行结果如下。

{'age': {'1': 'yes', '0': {'student': {'1': 'yes', '0': 'no'}}, '2': {'credit': {'1': 'no', '0': 'yes'}}}

决策树分类

最后我们给出决策树的分类器代码。

def predict(self,inputTree,featLabels,testVec):     # 分类器 
        root = inputTree.keys()[0]                              # 树根节点
        secondDict = inputTree[root]                            # value-子树结构或分类标签
        featIndex = featLabels.index(root)                      # 根节点在分类标签集中的位置
        key = testVec[featIndex]                                        # 测试集数组取值 
        valueOfFeat = secondDict[key]                            
        if isinstance(valueOfFeat, dict): 
            classLabel = self.predict(valueOfFeat, featLabels, testVec) # 递归分类
        else: classLabel = valueOfFeat
        return classLabel

下面我们随机给出一个潜在客户,即一个行向量,使用学习出的决策树进行分类。执行预测代码如下。

dtree = ID3DTree()
  
  labels = ["age","revenue","student","credit"]
  vector = ['0','1','0','0']    # ['0','1','0','0','no']
  mytree = dtree.grabTree("data.tree")
  print "真实输出 ","no","->","决策树输出",dtree.predict(mytree,labels,vector)

算法评估

D3算法是比较早的机器学习算法,在1979年Quinlan就提出了该算法的思想。它以信息熵为度量标准,划分出决策树特征节点,每次优先选取信息量最多的属性,也就是使信息熵变为最小的属性,以构造一棵信息熵下降最快的决策树。

但是ID3在使用中也暴露出了一些问题。

  • ID3算法的节点划分度量标准采用的是信息增益,信息增益偏向于选择特征值个数较多的特征。而取值个数较多的特征并不一定是最优的特征,所以需要改进选择属性的节点划分度量标准。
  • ID3算法递归过程中需要依次计算每个特征值的,对于大型数据会生成比较复杂的决策树:层次和分支都很多,而其中某些分支的特征值概率很小,如果不加忽略就会造成过拟合的问题。即决策树对样本数据的分类精度较高,但在测试集上,分类的结果受决策树分支的影响很大。
  • 7
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
ID3算法是一种决策树学习算法,用于分类和预测。下面是Python实现ID3算法的基本步骤: 1. 导入相应的库: ``` import pandas as pd import numpy as np import math ``` 2. 定义一个函数来计算数据集的熵: ``` def entropy(target_col): elements, counts = np.unique(target_col, return_counts=True) entropy = np.sum( [(-counts[i]/np.sum(counts)) * np.log2(counts[i]/np.sum(counts)) for i in range(len(elements))] ) return entropy ``` 3. 定义一个函数来计算数据集中每个特征的信息增益: ``` def info_gain(data, split_attribute_name, target_name="class"): total_ent = entropy(data[target_name]) vals, counts = np.unique(data[split_attribute_name], return_counts=True) weighted_ent = np.sum( [(counts[i]/np.sum(counts)) * entropy(data.where(data[split_attribute_name] == vals[i]).dropna()[target_name]) for i in range(len(vals))] ) info_gain = total_ent - weighted_ent return info_gain ``` 4. 定义一个函数来选择具有最高信息增益的特征: ``` def ID3(data, original_data, features, target_attribute_name="class", parent_node_class=None): if len(np.unique(data[target_attribute_name])) <= 1: return np.unique(data[target_attribute_name])[0] elif len(data) == 0: return np.unique(original_data[target_attribute_name])[ np.argmax(np.unique(original_data[target_attribute_name], return_counts=True)[1])] elif len(features) == 0: return parent_node_class else: parent_node_class = np.unique(data[target_attribute_name])[ np.argmax(np.unique(data[target_attribute_name], return_counts=True)[1])] item_values = [info_gain(data, feature, target_attribute_name) for feature in features] best_feature_index = np.argmax(item_values) best_feature = features[best_feature_index] tree = {best_feature: {}} features = [i for i in features if i != best_feature] for value in np.unique(data[best_feature]): sub_data = data.where(data[best_feature] == value).dropna() subtree = ID3(sub_data, original_data, features, target_attribute_name, parent_node_class) tree[best_feature][value] = subtree return tree ``` 5. 最后,我们使用训练数据来构建一棵决策树: ``` def train_test_split(dataset, split_ratio=0.8): train_size = int(split_ratio * len(dataset)) train_set = dataset.sample(train_size) test_set = dataset.drop(train_set.index) return train_set.reset_index(drop=True), test_set.reset_index(drop=True) data = pd.read_csv("dataset.csv") train_data, test_data = train_test_split(data) tree = ID3(train_data, train_data, train_data.columns[:-1]) ``` 这样我们就可以得到一个基本的ID3算法实现。需要注意的是,这个实现并不包括一些优化技巧,例如剪枝等,因此在实际应用中可能需要进行一定的修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值