决策树ID3算法不调包代码学习笔记

导入包

import numpy as np
import pandas as pd

定义一个数据集

def create_data():
    datasets = [['青年', '否', '否', '一般', '否'],
               ['青年', '否', '否', '好', '否'],
               ['青年', '是', '否', '好', '是'],
               ['青年', '是', '是', '一般', '是'],
               ['青年', '否', '否', '一般', '否'],
               ['中年', '否', '否', '一般', '否'],
               ['中年', '否', '否', '好', '否'],
               ['中年', '是', '是', '好', '是'],
               ['中年', '否', '是', '非常好', '是'],
               ['中年', '否', '是', '非常好', '是'],
               ['老年', '否', '是', '非常好', '是'],
               ['老年', '否', '是', '好', '是'],
               ['老年', '是', '否', '好', '是'],
               ['老年', '是', '否', '非常好', '是'],
               ['老年', '否', '否', '一般', '否'],
               ]
    labels = [u'年龄', u'有工作', u'有自己的房子', u'信贷情况', u'类别']
    #u: 表示unicode字符串,默认模式,里边的特殊字符会被识别。比如\t会识别为空格
    # 返回数据集和每个维度的名称
    return datasets, labels
datasets,labels=create_data()
train_data=pd.DataFrame(datasets,columns=labels)

定义Node,在下面调用时传回一个实例化对象。

#定义节点类,二叉树
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)

定义类DTree

class DTree:
    def __init__(self,epsilon=0.1):
        self.epsilon = epsilon
        self._tree = {}
    # 通过@staticmethod声明的,属于类的静态方法
    #对于类中的普通函数,当需要调用的时候必须实例化,对于声明为staticmethod/classmethod ,不需要实例化,直接使用类名调用。
    #熵
    @staticmethod
    def calc_ent(datasets):
        data_length =len(datasets)
        label_count={}
        for i in range(data_length):
            label = datasets[i][-1]
            if label not in label_count:
                label_count[label] = 0
            label_count[label] += 1
        ent = -sum([(p/data_length)*log(p/data_length,2) for p in label_count.values()])
        return ent

    #经验条件熵
    def cond_ent(self, datasets, axis=0):
        data_length = len(datasets)
        feature_sets = {}
        for i in range(data_length):
            feature = datasets[i][axis]
            if feature not in feature_sets:
                feature_sets[feature] = []
            feature_sets[feature].append(datasets[i])
        cond_ent = sum([(len(p)/data_length)*self.calc_ent(p) for p in feature_sets.values()])
        return cond_ent

    #信息增益
    @staticmethod
    def info_gain(ent, cond_ent):
        return ent - cond_ent

    def info_gain_train(self, datasets):
        count = len(datasets[0]) - 1
        ent = self.calc_ent(datasets)
        best_feature = []
        for c in range(count):
            c_info_gain = self.info_gain(ent, self.cond_ent(datasets, axis=c))
            best_feature.append((c, c_info_gain))
        # 比较大小
        best_ = max(best_feature, key=lambda x: x[-1]) #key定义了比较大小的位置,key还可以是某种运算函数,使最大值是使用函数后得到的
        return best_ #返回最大的索引和它对应的信息增益

    def train(self,train_data):
        """
        input:数据集D,特征集A,阈值eta
        output:决策树T
        """
        _,y_train,features = train_data.iloc[:,:-1],train_data.iloc[:,-1],train_data.columns[:-1] #y_train:是否贷款,features:列名
        #若D中实例属于同一类ck,则T为单节点树,并将类ck作为节点的类标记,返回T
        if len(y_train.value_counts())==1:
            return Node(root=Ture,label=y_train.iloc[0])#因为都是一类的,所以取第一个
        #若A为空,则T为单节点树,将D中实例树最大的类Ck作为该节点的类标记,返回T
        if len(features) == 0:
            return Node(root=True, label=y_train.value_counts().sort_values(ascending=False).index[0])
        #计算最大信息增益 同5.1,Ag为信息增益最大的特征
        max_feature, max_info_gain = self.info_gain_train(np.array(train_data))
        max_feature_name = features[max_feature]
        # Ag的信息增益小于阈值eta,则置T为单节点树,并将D中是实例数最大的类Ck作为该节点的类标记,返回T
        if max_info_gain < self.epsilon:
            return Node(root=True, label=y_train.value_counts().sort_values(ascending=False).index[0])

        # 构建Ag子集
        node_tree = Node(root=False, feature_name=max_feature_name, feature=max_feature)

        feature_list = train_data[max_feature_name].value_counts().index #max_feature_name那一列有几类
        for f in feature_list:
            sub_train_df = train_data.loc[train_data[max_feature_name] == f].drop([max_feature_name], axis=1) #比如把所有年龄是青年的数据提取出来后,再把年龄这列数据删了

            # 6, 递归生成树
            sub_tree = self.train(sub_train_df)
            node_tree.add_node(f, sub_tree)

        # pprint.pprint(node_tree.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)

使用数据集将其实现

datasets, labels = create_data()
data_df = pd.DataFrame(datasets, columns=labels)
dt = DTree() #类实例化
tree = dt.fit(data_df)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值