首页 > 编程语言 >实验一:决策树算法实验

实验一:决策树算法实验

时间:2022-10-24 16:02:58浏览次数:77  
标签:datasets self feature 算法 train 实验 ent data 决策树

博客班级 https://edu.cnblogs.com/campus/czu/classof2020BigDataClass3-MachineLearning
作业要求 https://edu.cnblogs.com/campus/czu/classof2020BigDataClass3-MachineLearning/homework/12858
学号 181613146

【实验目的】

  1. 理解决策树算法原理,掌握决策树算法框架;
  2. 理解决策树学习算法的特征选择、树的生成和树的剪枝;
  3. 能根据不同的数据类型,选择不同的决策树算法;
  4. 针对特定应用场景及数据,能应用决策树算法解决实际问题。

【实验内容】

  1. 设计算法实现熵、经验条件熵、信息增益等方法。
  2. 针对给定的房贷数据集(数据集表格见附录1)实现ID3算法。
  3. 熟悉sklearn库中的决策树算法。
  4. 针对iris数据集,应用sklearn的决策树算法进行类别预测。

【实验报告要求】

  1. 对照实验内容,撰写实验过程、算法及测试结果;
  2. 代码规范化:命名规则、注释;
  3. 查阅文献,讨论ID3、C4.5算法的应用场景;
  4. 查询文献,分析决策树剪枝策略。

【附录1】

年龄 有工作 有自己的房子 信贷情况 类别
0 青年 一般
1 青年
2 青年
3 青年 一般
4 青年 一般
5 中年 一般
6 中年
7 中年
8 中年 非常好
9 中年 非常好
10 老年 非常好
11 老年
12 老年
13 老年 非常好
14 老年 一般

【实验过程与步骤】

决策树

  • ID3(基于信息增益)

  • C4.5(基于信息增益比)

  • CART(gini指数)

熵(entropy):$ H(x)=\ -\sum_{i=1}^{n}p_{i}\log p_{i} $

条件熵(conditional entropy): $H(X|Y)=\sum P(X|Y)\log P(X|Y)$

信息增益(information gain) : $g(D,;A)=H(D)-H(D|A)$

信息增益率(information gain ratio): $g_{R}(D,;A)={\frac{g(D,;A)}{H(A)}}$

基尼指数(gini index): $G i n i({\cal D})=\sum_{k}{K}=1;p_{k}\log{p_{k}}=1-\sum_{k=1}{K}p_{k}^{2}$

1. 设计算法实现熵、经验条件熵、信息增益等方法:

# 导入需要的包
import numpy as np
import pandas as pd
import math
from math import log
  • 创建数据
# 数据集和分类属性
 
def create_data():
    datasets = [['青年', '否', '否', '一般', '否'],  # 数据集
                ['青年', '否', '否', '好', '否'],
                ['青年', '是', '否', '好', '是'],
                ['青年', '是', '是', '一般', '是'],
                ['青年', '否', '否', '一般', '否'],
                ['中年', '否', '否', '一般', '否'],
                ['中年', '否', '否', '好', '否'],
                ['中年', '是', '是', '好', '是'],
                ['中年', '否', '是', '非常好', '是'],
                ['中年', '否', '是', '非常好', '是'],
                ['老年', '否', '是', '非常好', '是'],
                ['老年', '否', '是', '好', '是'],
                ['老年', '是', '否', '好', '是'],
                ['老年', '是', '否', '非常好', '是'],
                ['老年', '否', '否', '一般', '否'],]
 
    labels = [u'年龄', u'有工作', u'有自己的房子', u'信贷情况', u'类别']  # 分类属性
 
    return datasets, labels  # 返回数据集和分类属性
 
# 将数据集转为DataFrame表格
datasets, labels = create_data()
train_data = pd.DataFrame(datasets, columns=labels)
train_data

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(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) * calc_ent(p)
                    for p in feature_sets.values()])
calc_ent(datasets)

  • 信息增益
def info_gain(ent, cond_ent):
    return ent - cond_ent
def info_gain_train(datasets):
    count = len(datasets[0]) - 1
    ent = calc_ent(datasets)
    best_feature = []
    for c in range(count):
        c_info_gain = info_gain(ent, cond_ent(datasets, axis=c))
        best_feature.append((c, c_info_gain))
        print('特征({}) 的信息增益为: {:.3f}'.format(labels[c], c_info_gain))
    # 比较大小
    best_ = max(best_feature, key=lambda x: x[-1])
    return '特征({})的信息增益最大,选择为根节点特征'.format(labels[best_[0]])
info_gain_train(np.array(datasets))

2. 针对给定的房贷数据集(数据集表格见附录1)实现ID3算法:

# 定义节点类 二叉树
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 DTree:
    def __init__(self, epsilon=0.1):
        self.epsilon = epsilon
        self._tree = {}

    # 熵
    @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])
        return best_

    def train(self, train_data):
        """
        input:数据集D(DataFrame格式),特征集A,阈值eta
        output:决策树T
        """
        _, y_train, features = train_data.iloc[:, :
                                               -1], train_data.iloc[:,
                                                                    -1], train_data.columns[:
                                                                                            -1]
        # 1,若D中实例属于同一类Ck,则T为单节点树,并将类Ck作为结点的类标记,返回T
        if len(y_train.value_counts()) == 1:
            return Node(root=True, label=y_train.iloc[0])

        # 2, 若A为空,则T为单节点树,将D中实例树最大的类Ck作为该节点的类标记,返回T
        if len(features) == 0:
            return Node(
                root=True,
                label=y_train.value_counts().sort_values(
                    ascending=False).index[0])

        # 3,计算最大信息增益 同5.1,Ag为信息增益最大的特征
        max_feature, max_info_gain = self.info_gain_train(np.array(train_data))
        max_feature_name = features[max_feature]

        # 4,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])

        # 5,构建Ag子集
        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)

            # 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)
tree

dt.predict(['老年', '否', '否', '一般'])

3. 熟悉sklearn库中的决策树算法:

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

使用Iris数据集,我们可以构建如下树:

# data
def create_data():
    iris = load_iris()
    df = pd.DataFrame(iris.data, columns=iris.feature_names)
    df['label'] = iris.target
    df.columns = [
        'sepal length', 'sepal width', 'petal length', 'petal width', 'label'
    ]
    data = np.array(df.iloc[:100, [0, 1, -1]])
    # print(data)
    return data[:, :2], data[:, -1],iris.feature_names[0:2]


X, y,feature_name= create_data()
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

4. 针对iris数据集,应用sklearn的决策树算法进行类别预测:

决策树分类

from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import export_graphviz
import graphviz
from sklearn import tree

clf = DecisionTreeClassifier()
clf.fit(X_train, y_train,)

clf.score(X_test, y_test)

![](https%3A%2F%2Fimg.wanganfeng.com%2FImage-resp%2F202210241534552.png

一旦经过训练,就可以用 plot_tree函数绘制树:

tree.plot_tree(clf) 

也可以导出树

tree_pic = export_graphviz(clf, out_file="mytree.pdf")
with open('mytree.pdf') as f:
    dot_graph = f.read()
graphviz.Source(dot_graph)

ID3、C4.5算法的应用场景

ID3算法应用场景:

它的基础理论清晰,算法比较简单,学习能力较强,适于处理大规模的学习问题,是数据挖掘和知识发现领域中的一个很好的范例,为后来各学者提出优化算法奠定了理论基础。ID3算法特别在机器学习、知识发现和数据挖掘等领域得到了极大发展。

C4.5算法应用场景:

C4.5算法具有条理清晰,能处理连续型属性,防止过拟合,准确率较高和适用范围广等优点,是一个很有实用价值的决策树算法,可以用来分类,也可以用来回归。C4.5算法在机器学习、知识发现、金融分析、遥感影像分类、生产制造、分子生物学和数据挖掘等领域得到广泛应用。

决策树剪枝策略

剪枝的目的在于:缓解决策树的"过拟合",降低模型复杂度,提高模型整体的学习效率
(决策树生成学习局部的模型,而决策树剪枝学习整体的模型)

基本策略:

  • 预剪枝:是指在决策树生成过程中,对每一个结点在划分前进行估计,若当前结点的划分不能带来决策树泛化性能提升,则停止划分并将当前结点标记为叶子结点。
    优点:降低了过拟合地风险,并显著减少了决策树地训练时间开销和测试时间开销。
    缺点:有些分支地当前划分虽不能提升泛化性能、甚至可能导致泛化性能下降,但是在其基础上进行地后续划分却可能导致性能显著提高;
    预剪枝基于'贪心'本质禁止这些分支展开,给预剪枝决策树带来了欠拟合的风险。
  • 后剪枝:先从训练集生成一棵完整的决策树,然后自底向上地对非叶子结点进行考察,若将该结点对应地子树替换为叶结点能带来决策树泛化性能提升,则将该子树替换为叶结点。
    优点:一般情况下后剪枝决策树的欠拟合风险很小,泛化性能往往优于预剪枝决策树。
    缺点:自底向上的注意考察,时间开销较高。

【实验小结】

实验中遇到的问题

在使用pip安装graphviz这个包后,发现还是报错。后经搜索了解,这只安装了graphviz的pyhon调用接口,使用的话还需要下载并安装graphviz的安装文件。随后卸载重装pip中的graphviz包。

标签:datasets,self,feature,算法,train,实验,ent,data,决策树
From: https://www.cnblogs.com/wanganfeng/p/16821731.html

相关文章

  • 实验二
    test1#include<stdio.h>#include<stdlib.h>#include<time.h>#defineN5intmain(){intnumber;inti;srand(time(0));for(i=0;i<N;++i){......
  • EM算法
    #1,求观测序列的概率#2,已知状态序列求观测序列#3,已知观测序列求模型参数#设状态值概率#pA=0.6#pB=0.5classEM():def__init__(self):self.t=0.6......
  • 实验5:开源控制器实践——POX
    (一)基本要求1.搭建下图所示SDN拓扑,协议使用OpenFlow1.0,控制器使用部署于本地的POX(默认监听6633端口)sudomn--topo=single,3--mac--controller=remote,ip=127.0.0.1,......
  • DFA算法C#实现
    ///<summary>///过滤词DFA算法实现///</summary>publicclassForbiddentWordLibrary{///<summary>///用分行过滤词文件来初......
  • 常用限流算法总结
    一、限流是什么?限流,也称流量控制。是指系统在面临高并发,或者大流量请求的情况下,限制新的请求对系统的访问,从而保证系统的稳定性。限流会导致部分用户请求处理不及时或者被......
  • 巡路算法
    比较闲,看了网上的思路后写了一个玩玩publicclassMapManager{privateintmapMaxX=0;privateintmapMaxY=0;privateint[,]mapInfo;//终点......
  • 贝叶斯过滤算法
    朴素贝叶斯分类是一种十分简单的分类算法,叫它朴素贝叶斯分类是因为这种方法的思想真的很朴素,朴素贝叶斯的思想基础是这样的:对于给出的待分类项,求解在此项出现的条件下各个类......
  • EMA算法的C#实现
    EMA表示的是指数平滑移动平均,其函数的定义为Y=EMA(X,N)则Y=[2*X+(N-1)*Y']/(N+1),其中Y'表示上一周期Y值。求X的N日指数平滑移动平均,它真正的公式表达是:当日指数平均值=平......
  • 实验三
    实验3数组、指针与现代c++标准库一、task51.源代码:(1)Info.cpp#include<iostream>#include<string>#include<iomanip>usingnamespacestd;classinfo{public:......
  • 对多分类任务中的模型评估隐藏层层数和隐藏单元个数对实验结果的影响
    8、对多分类任务中的模型评估隐藏层层数和隐藏单元个数对实验结果的影响1.确定隐藏层的层数对于一些很简单的数据集,一层甚至两层隐藏元都已经够了,隐藏层的层数不一定设置......