美文网首页
ID3算法实现决策树

ID3算法实现决策树

作者: bokli_dw | 来源:发表于2020-03-18 15:47 被阅读0次

1.ID.3算法

1.1算法原理:

算法的核心是在决策树各个节点上,应用信息增益准则选择特征,递归的构建决策树。
算法是一种经典的决策树学习算法,由Quinlan于1979年提出。算法主要针对属性选择问题。是决策树学习方法中最具影响和最为典范的算法,该方法使用信息增益选择测试属性。当获取信息时将不确定的内容转为确定的内容,因此信息伴随不确定性,从直觉上讲,小概率事件比大概率事件包含的信息量更大,如果某件事情是百年一见,这肯定比习以为常的事件包含的信息量大。
如何度量信息量的大小呢?信息增益。

具体方法是:
下面内容引用自《李航统计学习方法》

从根节点开始对节点计算所有可能的特征的信息增益,选择信息增益最大的特征作为节点的特征,由该特征的不同取值建立此节点,再对子节点递归的调用以上方法构建决策树,直到所有特征的信息增益均最小或没有特征可以选择为止,最后得到一棵决策树,相当于用极大似然法进行概率模型的选择。

ID3算法

输入:训练数据集、特征集和阈值。
输出:决策树。
1)若D中所有实例属于同一类Ck,则T为单结点树,并将类Ck于作为该结点的类标记,返回T。
2)若A等于空集,则T为单节点数,并将D中实例数最大的类似于作为该结点的类标记返回T。
3)否则,计算A中各特征对D的信息增益选择信息增益最大的特征Ag.
4)如果Ag的信息增益小于阈值,则置T为单结点树必将D中实例数最大的类Ck作为该结点的类标记返回T。否则对Ag的每一个可能值Ai,依Ag等于Ai将D分割为若干非空子集Di,将Di中实例数最大的类作为标记,构建子结点,由结点及其子结点构成树T,返回T。
5)对第i个子结点,以Di为训练集以A-{Ag}为特征集递归的调用步骤1)到步骤5),得到子树Ti,返回Ti。

熵的公式:H(x)=-\sum_{i=1}^{n}p_i\log{p_i}
条件熵计算公式: H(X|Y)=\sum{P(X|Y)\log{P(X|Y)}}
信息增益: g(D,A)=H(D)-H(D|A)
Gini系数: Gini(D)=\sum_{k=1}^{K}p_k\log{p_k}=1-\sum_{k=1}^{K}p_k^2

1.2 下面以鸢尾花数据集开始实现ID3算法吧!

首先,导包!

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

然后,让我们来定义两个类:Node和DeciTree

class Node:
    def __init__(self,root=True,label = None, feature_name=None, feature=None):
        self.root = root
        self.label = label
        self.feature_name = feature_name
        self.feature = feature
        self.tree = {}
        self.result = {"label":self.label,
                      "feature":self.feature,
                      "tree":self.tree}
    
    def __repr__(self):
        return '{}'.format(self.result)
    
    def add_node(self,val,node):
        self.tree[val] = node
        
    def predict(self,features):
        if self.root is True:
            return self.label
        return self.tree[features[self.feature]].predict(features)
    
    
class DeciTree:
    def __init__(self,epsilon=0.1):
        self.epsilon = epsilon
        self._tree = {}
    @staticmethod
    def calculate_entropy(datasets):
        length = len(datasets)
        label_count = {}
        for i in range(length):
            label = datasets[i][-1]
            if label not in label_count:
                label_count[label] = 0    
            label_count[label] +=1
            
        entropy = -sum([(p/length)*log(p/length,2) for p in label_count.values()])
        return entropy
    
    def cal_cond_entropy(self,datasets,axis =0):
        length = len(datasets)
        feature_sets = {}
        for c in range(length):
            feature = datasets[c][axis]
            if feature not in feature_sets:
                feature_sets[feature] =[]
            feature_sets[feature].append(datasets[c])
            
        cond_entropy = sum([(len(p)/length)*self.calculate_entropy(p) for p in feature_sets.values()])
        
        return cond_entropy
    @staticmethod
    def info_gain(entropy,cond_entropy):
        return entropy-cond_entropy
    
    def info_gain_train(self,datasets):
        count = len(datasets[0])-1
        entropy = self.calculate_entropy(datasets)
        best_feature = []
        
        for c in range(count):
            c_info_gain = self.info_gain(entropy,self.cal_cond_entropy(datasets,axis=c))
            best_feature.append((c,c_info_gain))
            
        best_ = max(best_feature, key = lambda x:x[-1])
        return best_
        
        
    def train(self,train_data):
        
        _,y_train,features = train_data.iloc[:,:-1],train_data.iloc[:,-1],train_data.columns[:-1]
        #step1,对应上述ID3算法中的1)
        if len(y_train.value_counts())==1:
            return Node(root=True
                       ,label = y_train.iloc[0])
        #step2对应上述ID3算法中的2)
        if len(features)==0:
            return Node(root=True
                       ,label = y_train.value_counts().sort_values(ascending=False).index[0])
        #step3 对应上述ID3算法中的3)
        max_feature,max_info_gain = self.info_gain_train(np.array(train_data))
        max_feature_name = features[max_feature]
        
        #step4 对应上述ID3算法中的4)
        if max_info_gain < self.epsilon:
            return Node(root=True
                       ,label=y_train.value_counts().sort_values(ascending=False).index[0])
        
        #step5 对应上述ID3算法中的5)
        node_tree = Node(root=False
                        ,feature_name = max_feature_name
                        ,feature=max_feature)
        
        feature_list = train_data[max_feature_name].value_counts().index
        
        for f in feature_list:
            sub_train_df = train_data.loc[train_data[max_feature_name]==f].drop([max_feature_name],axis=1)
            sub_tree = self.train(sub_train_df)
            node_tree.add_node(f,sub_tree)
            
        return node_tree
    
    def fit(self,train_data):
        self._tree = self.train(train_data)
        return self._tree
    
    def predict(self,x_test):
        return self._tree.predict(x_test)

数据处理
获得数据集,转换数据的类型为Dateframe并将数据“合并成一张表”。

#下载数据集iris
iris = load_iris()
#print(iris.feature_names)
data,target = iris.data,iris.target
data = pd.DataFrame(data,columns=iris.feature_names)
target = pd.DataFrame(target)
datasets= data.join(target)

1.3 实例化喂数据

dt = DeciTree()
tree = dt.fit(datasets)
tree

运行结果将这棵树以字典的形式打印出来。

2.使用sklearn实现决策树

step1 一如既往的从导包开始。

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from sklearn import tree
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

step2 数据预处理

#下载数据集iris
iris = load_iris() #下载原始数据集
#print(iris.feature_names) out: ['sepal length', 'sepal width', 'petal length', 'petal width']
data,target = iris.data,iris.target
data = pd.DataFrame(data,columns=iris.feature_names)#转化数据的数据类型
target = pd.DataFrame(target)
datasets= data.join(target)
#datasets.info()
#datasets.head() 查看前五个数据

step3 种下一棵树
实例化分类器,训练分类器

x_train,x_test,y_train,y_test = train_test_split(data,target,test_size = 0.3)
clf = tree.DecisionTreeClassifier(criterion="gini") #实例化分类器。
clf.fit(x_train, y_train)                            #通过接口为数据。
score = clf.score(x_test, y_test)                    #查看分类器的性能

step4 把树画出来吧!

feature_name=['sepal length', 'sepal width', 'petal length', 'petal width']
from sklearn.tree import export_graphviz
import graphviz
fig_data = export_graphviz(clf
                          ,feature_names = feature_name
                           ,class_names = ['0:setosa', '1:virginica','2:versicolor']
                           ,filled = True
                           ,rounded = True)
                           #out_file = "my_tree.pdf")
graph = graphviz.Source(fig_data)

树长这样


决策树(鸢尾花数据集)

相关文章

网友评论

      本文标题:ID3算法实现决策树

      本文链接:https://www.haomeiwen.com/subject/oxzqyhtx.html