实验一:决策树算法实验

一、【实验目的】

理解决策树算法原理,掌握决策树算法框架;
理解决策树学习算法的特征选择、树的生成和树的剪枝;
能根据不同的数据类型,选择不同的决策树算法;


针对特定应用场景及数据,能应用决策树算法解决实际问题。
二、【实验内容】

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

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

年龄 有工作 有自己的房子 信贷情况 类别

0 青年 否 否 一般 否
1 青年 否 否 好 否
2 青年 是 否 好 是
3 青年 是 是 一般 是
4 青年 否 否 一般 否
5 中年 否 否 一般 否
6 中年 否 否 好 否
7 中年 是 是 好 是
8 中年 否 是 非常好 是
9 中年 否 是 非常好 是
10 老年 否 是 非常好 是
11 老年 否 是 好 是
12 老年 是 否 好 是
13 老年 是 否 非常好 是
14 老年 否 否 一般 否

 

四、实验内容及结果

实验代码及截图

1、决策树

(1)导包

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
from collections import Counter
import math
from math import log

 

  

(2)创建数据

def createDataSet():
    dataSet = [[0, 0, 0, 0, 'no'],  # 数据集
               [0, 0, 0, 1, 'no'],
               [0, 1, 0, 1, 'yes'],
               [0, 1, 1, 0, 'yes'],
               [0, 0, 0, 0, 'no'],
               [1, 0, 0, 0, 'no'],
               [1, 0, 0, 1, 'no'],
               [1, 1, 1, 1, 'yes'],
               [1, 0, 1, 2, 'yes'],
               [1, 0, 1, 2, 'yes'],
               [2, 0, 1, 2, 'yes'],
               [2, 0, 1, 1, 'yes'],
               [2, 1, 0, 1, 'yes'],
               [2, 1, 0, 2, 'yes'],
               [2, 0, 0, 0, 'no']]
    labels = ['年龄', '有工作', '有自己的房子', '信贷情况','类别']  # 分类属性
    return dataSet, labels
dataSet,labels = createDataSet()
train_data = pd.DataFrame(dataSet, columns=labels)
train_data

 

(3)计算信息熵

def splitDataSet(dataSet, axis, value):
    retDataSet = []  # 创建返回的数据集列表
    for featVec in dataSet:  # 遍历数据集
        if featVec[axis] == value:
            reducedFeatVec = featVec[:axis]  # 去掉axis特征
            reducedFeatVec.extend(featVec[axis + 1:])  # 将符合条件的添加到返回的数据集
            retDataSet.append(reducedFeatVec)
    return retDataSet  # 返回划分后的数据集

def chooseBestFeatureToSplit(dataSet):
    numFeatures = len(dataSet[0]) - 1  # 特征数量
    baseEntropy = calcShannonEnt(dataSet)  # 计算数据集的香农熵
    bestInfoGain = 0.0  # 信息增益
    bestFeature = -1  # 最优特征的索引值
    for i in range(numFeatures):  # 遍历所有特征
        # 获取dataSet的第i个所有特征
        featList = [example[i] for example in dataSet]
        uniqueVals = set(featList)  # 创建set集合{},元素不可重复
        newEntropy = 0.0  # 经验条件熵
        for value in uniqueVals:  # 计算信息增益
            subDataSet = splitDataSet(dataSet, i, value)  # subDataSet划分后的子集
            prob = len(subDataSet) / float(len(dataSet))  # 计算子集的概率
            newEntropy += prob * calcShannonEnt(subDataSet)  # 根据公式计算经验条件熵
        infoGain = baseEntropy - newEntropy  # 信息增益
        print(u"第%i特征信息的信息增量为:%.3f"%(i,infoGain))  # 打印每个特征的信息增益
        if (infoGain > bestInfoGain):  # 计算信息增益
            bestInfoGain = infoGain  # 更新信息增益,找到最大的信息增益
            bestFeature = i  # 记录信息增益最大的特征的索引值
    return bestFeature  # 返回信息增益最大的特征的索引值

def majorityCnt(classList):
    classCount = {}
    for vote in classList:  # 统计classList中每个元素出现的次数
        if vote not in classCount.keys():
            classCount[vote] = 0
        classCount[vote] += 1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)  # 根据字典的值降序排序
    return sortedClassCount[0][0]  # 返回classList中出现次数最多的元素

 

(4)创建决策树

def createTree(dataSet, labels, featLabels):
    classList = [example[-1] for example in dataSet]  # 取分类标签(是否放贷:yes or no)
    if classList.count(classList[0]) == len(classList):  # 如果类别完全相同则停止继续划分
        return classList[0]
    if len(dataSet[0]) == 1:  # 遍历完所有特征时返回出现次数最多的类标签
        return majorityCnt(classList)
    bestFeat = chooseBestFeatureToSplit(dataSet)  # 选择最优特征
    bestFeatLabel = labels[bestFeat]  # 最优特征的标签
    featLabels.append(bestFeatLabel)
    print(u"此时最优索引为:"+str(bestFeatLabel))
    myTree = {bestFeatLabel: {}}  # 根据最优特征的标签生成树
    del (labels[bestFeat])  # 删除已经使用特征标签
    featValues = [example[bestFeat] for example in dataSet]  # 得到训练集中所有最优特征的属性值
    uniqueVals = set(featValues)  # 去掉重复的属性值
    for value in uniqueVals:
        subLabels = labels[:]
        # 递归调用函数createTree(),遍历特征,创建决策树。
        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels, featLabels)
    return myTree

def classify(inputTree, featLabels, testVec):
    firstStr = next(iter(inputTree))  # 获取决策树结点
    secondDict = inputTree[firstStr]  # 下一个字典
    featIndex = featLabels.index(firstStr)
    for key in secondDict.keys():
        if testVec[featIndex] == key:
            if type(secondDict[key]).__name__ == 'dict':
                classLabel = classify(secondDict[key], featLabels, testVec)
            else:
                classLabel = secondDict[key]
    return classLabel
if __name__ == '__main__':
    dataSet, labels = createDataSet()
    featLabels = []
    myTree = createTree(dataSet, labels, featLabels)
    print(myTree)
    testVec = [0,0]  # 测试数据
    result = classify(myTree, featLabels, testVec)
    if result == 'yes':
        print('放贷')
    if result == 'no':
        print('不放贷')

 

 

2、运用sklearn生成决策树

import numpy as np
from sklearn import tree
import graphviz #画图需要自己安装
dataset=[                   # 数据集
    [1,0,0,1,0],
    [1,0,0,2,0],
    [1,1,0,2,1],
    [1,1,1,1,1],
    [1,0,0,1,0],
    [2,0,0,2,0],
    [2,0,0,2,0],
    [2,1,1,2,1],
    [2,0,1,3,1],
    [2,0,1,2,1],
    [3,0,1,3,1],
    [3,0,1,2,1],
    [3,1,0,3,1],
    [3,1,0,3,1],
    [3,0,0,1,0]
]
feature =['年龄','没有工作','没有自己的房子','信贷情况']
classname =['不放贷','放贷']

X = [x[0:4] for x in dataset]
print(X)
Y = [y[-1] for y in dataset]
print(Y)
tree_clf = DecisionTreeClassifier(max_depth=4) # 最深分为4层
tree_clf.fit(X, Y)

dot_data = tree.export_graphviz(  #实现可视化
            tree_clf,
            out_file=None,
            feature_names=feature,
            class_names=classname,
            rounded=True,
            filled=True,

        )

graph = graphviz.Source(dot_data)
graph

 

 

 

 

 

3.运用sklearn中iris数据集创建决策树进行测试

(1)导包及测试

from sklearn import tree #导入树
from sklearn.tree import DecisionTreeClassifier #导入决策树分类器
from sklearn.datasets import load_iris #导入鸢尾花数据集
from sklearn.model_selection import train_test_split #分训练集测试集的类
import pandas as pd 
iris = load_iris() #将数据集实例化,别忘了括号
Xtrain,Xtest,Ytrain,Ytest = train_test_split(iris.data,iris.target,test_size=0.3) 
#实例化模型,括号不填criterion默认是‘gini’,也可以填criterion = 'entropy'
clf = DecisionTreeClassifier()
#训练数据集
clf = clf.fit(Xtrain, Ytrain) 
#评估数据集
score = clf.score(Xtest, Ytest) 
score #将评估结果打印出来,因为测试集和训练集划分的不同,可能每个人的结果也不同

 

(2)实现可视化,画出决策树

import graphviz 
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import export_graphviz
dot_data=tree.export_graphviz(clf,out_file=None,
                              feature_names=iris.feature_names,
                              class_names=True,filled=False,rounded=True)

graph = graphviz.Source(dot_data)
graph

 

 

 

五、实验问题与解决方法

问题:实现可视化的时候出现了:No module named 'graphive',

解决方法:下载graphviz软件后,在Anaconda Prompt下输入conda install python-graphviz安装

 

六、实验小结

(1)、讨论ID3和C4.5算法的应用场景

1、ID3应用场景

ID3算法的核心是在决策树各个结点上应用信息增益准则选择特征,递归地构建决策树,他的优点总的来说,就是理论清晰、方法简单、学习能力较强,他已被广泛应用于数据挖掘和人工智能中,也常用于机器学习和自然语言处理领域,得到了极大的发展

2、C4.5应用场景

C4.5算法与ID3算法一样使用了信息熵的概念,ID3使用的是熵的变化值,而C4.5用的是信息增益率,可分类也可回归,他的优点条理清晰,防止过拟合,产生的分类规则易于理解,准确率较高。在机器学习,金融分析,遥感影响,数据挖掘等领域得到广泛应用

 

(2)、分析决策树剪枝策略

剪枝是决策树算法对付过拟合的主要手段。因为决策树在划分过程中为了尽可能正确分类训练样本,可能会不断重复,产生过拟合现象。

预剪枝:是在决策树的生成过程中,对每个结点在划分前先进行估计,若当前结点的划分不能带来决策树泛化性能提升,则停止划分即结束树的构建并将当前节点标记为叶结点;
优点:这不仅降低了过拟合的风险,还显著减少了决策树的训练时间开销和测试时间开销。
缺点:预剪枝基于“贪心”本质禁止这些分支展开,给预剪枝决策树带来了欠拟合的风险。

后剪枝:是先从训练集生成一棵完整的决策树,然后自底向上地对叶结点进行考察,若将该结点对应的子树替换为叶结点能带来决策树泛化为性能提升,则将该子树替换为叶结点。
优点:有效避免欠拟合现象,正确率较高。
缺点:需要先生成完整的决策树,开销大

 

posted @ 2022-10-24 11:30  “su"ning  阅读(856)  评论(0编辑  收藏  举报