决策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性的决策分析方法,是直观运用概率分析的一种图解法。由于这种决策分支画成图形很像一棵树的枝干,故称决策树。

简单说就是依据熵值计算,不断地做出选择,直到获得最终结果(熵值为0或者在设定的某个范围内)。根据计算方法不同,有ID3算法、C4.5算法、CART算法等。

每个对象就是一个节点,开始的地方叫根节点,最后不能分的地方叫叶子节点。

剪枝

剪枝是决策树停止分支的方法之一,剪枝有分预先剪枝和后剪枝两种。

预先剪枝是在树的生长过程中设定一个指标,当达到该指标时就停止生长,这样做容易产生“视界局限”,就是一旦停止分支,使得节点N成为叶节点,就断绝了其后继节点进行“好”的分支操作的任何可能性。

后剪枝中树首先要充分生长,直到叶节点都有最小的不纯度值为止,因而可以克服“视界局限”,而且无需保留部分样本用于交叉验证,所以可以充分利用全部训练集的信息。但后剪枝的计算量代价比预剪枝方法大得多,特别是在大样本集中,不过对于小样本的情况,后剪枝方法还是优于预剪枝方法的。

ID3算法

以信息增益为准则来选择划分属性,选择划分后信息增益最大的属性进行划分,这种算法对属性可取数目较多时有偏好。

这里举个例子,比如说有个女生要选相亲对象,相亲对象有收入(income)、身高(hight)、长相(look)、体型(shape)等条件可以考察,那么我们用ID3算法来分析以下她的决策。

我们收集了她之前研究过的几十个相亲对象和决策情况,如下表,我们把它保存为文件data01.csv

收入 身高 长相 体型 是否见面
一般
普通
一般
匀称
匀称
普通
一般 普通 匀称
普通 匀称
一般
普通
一般
一般 普通 匀称
一般 普通
一般
一般 匀称
普通
普通
普通
一般 匀称
普通
一般

然后我们用ID3算法来分析:

from math import log
import operator
import numpy as np
import pandas as pd
from pandas import DataFrame, Series
#构建决策和数字的映射
productDict = {'高':1,'一般':2,'低':3,'中':2, '帅':1, '普通':2, '丑':3, '胖':3, '匀称':2,'瘦':1, '是':1, '否':0}
#导入数据
def Importdata(datafile): dataa = pd.read_excel(datafile)  # datafile是excel文件,所以用read_excel,如果是csv文件则用read_csv#将文本中不可直接使用的文本变量替换成数字dataa['income'] = dataa['收入'].map(productDict)  # 将每一列中的数据按照字典规定的转化成数字dataa['hight'] = dataa['身高'].map(productDict)dataa['look'] = dataa['长相'].map(productDict)dataa['shape'] = dataa['体型'].map(productDict)dataa['is_meet'] = dataa['是否见面'].map(productDict)data = dataa.iloc[:,5:].values.tolist()  # 取量化后的几列,去掉文本列b = dataa.iloc[0:0,5:-1]labels = b.columns.values.tolist()  # 将标题中的值存入列表中return data,labels#计算数据的熵(entropy)--原始熵
def dataentropy(data, feat):  lendata = len(data)  # 数据条数labelCounts = {}  # 数据中不同类别的条数for featVec in data:category = featVec[-1]  # 每行数据的最后一个字(叶子节点)if category not in labelCounts.keys():labelCounts[category] = 0 labelCounts[category] += 1  # 统计有多少个类以及每个类的数量entropy = 0for key in labelCounts:prob = float(labelCounts[key]) / lendata  # 计算单个类的熵值entropy -= prob * log(prob,2)  # 累加每个类的熵值return entropy#对数据按某个特征value进行分类
def splitData(data,i,value): splitData = []for featVec in data:if featVec[i] == value:rfv = featVec[:i]rfv.extend(featVec[i+1:])splitData.append(rfv)return splitData#选择最优的分类特征
def BestSplit(data):  numFea = len(data[0]) - 1  # 计算一共有多少个特征,因为最后一列一般是分类结果,所以需要-1baseEnt = dataentropy(data,-1)   # 定义初始的熵,用于对比分类后信息增益的变化bestInfo = 0bestFeat = -1for i in range(numFea):featList = [rowdata[i] for rowdata in data]uniqueVals = set(featList)newEnt = 0for value in uniqueVals:subData = splitData(data,i,value)  # 获取按照特征value分类后的数据prob = len(subData) / float(len(data))newEnt += prob * dataentropy(subData,i)  # 按特征分类后计算得到的熵info = baseEnt - newEnt  # 原始熵与按特征分类后的熵的差值,即信息增益if (info > bestInfo):   # 若按某特征划分后,若infoGain大于bestInf,则infoGain对应的特征分类区分样本的能力更强,更具有代表性。 bestInfo = info  # 将infoGain赋值给bestInf,如果出现比infoGain更大的信息增益,说明还有更好地特征分类bestFeat = i  # 将最大的信息增益对应的特征下标赋给bestFea,返回最佳分类特征return bestFeat #按分类后类别数量排序,取数量较大的
def majorityCnt(classList):    c_count = {}for i in classList:if i not in c_count.keys():c_count[i] = 0c_count[i] += 1ClassCount = sorted(c_count.items(),key=operator.itemgetter(1),reverse=True) # 按照统计量降序排序return ClassCount[0][0]  # reverse=True表示降序,因此取[0][0],即最大值#构建树
def createTree(data,labels):classList = [rowdata[-1] for rowdata in data]  # 取每一行的最后一列,分类结果(1/0)#print(classList)if classList.count(classList[0]) == len(classList):return classList[0]if len(data[0]) == 1:return majorityCnt(classList)bestFeat = BestSplit(data)  # 根据信息增益选择最优特征bestLab = labels[bestFeat]myTree = {bestLab:{}}  # 分类结果以字典形式保存del(labels[bestFeat])featValues = [rowdata[bestFeat] for rowdata in data]uniqueVals = set(featValues)for value in uniqueVals:subLabels = labels[:]myTree[bestLab][value] = createTree(splitData(data,bestFeat,value),subLabels)return myTree#主程序
datafile = 'data/dateperson/date01.xlsx'  # 文件所在位置
data, labels = Importdata(datafile)  # 导入数据jc=createTree(data, labels)  # 输出决策树模型结果print(jc)

执行之后得到如下结果:

PS C:\coding\machinelearning>ID3相亲决策实验.py
{'income': {1: 1, 2: {'hight': {1: {'look': {1: 1, 2: 1, 3: {'shape': {0: 0, 1: 1}}}}, 2: 1, 3: 0}}, 3: {'hight': {1: {'look': {2: 1, 3: 0}}, 2: 0, 3: 0}}}}
PS C:\coding\machinelearning>

从结果来看,小姐姐找相亲对象,首先看收入,收入高的一定见,收入中等的再看身高、长相等。收入低的除非又高又帅,否则免谈。

C4.5算法

选择具有最大增益率的属性作为划分属性,具体做法是先从候选划分属性中找到信息增益高于平均水平的属性,再从中选择增益率最高的作为划分属性。

下面再用C4.5算法把上面小姐姐相亲的例子再算一遍

from math import log
import operator
import numpy as np
import pandas as pd
from pandas import DataFrame, Series
productDict = {'高':1,'一般':2,'低':3,'中':2, '帅':1, '普通':2, '丑':3, '胖':3, '匀称':2,'瘦':1, '是':1, '否':0}
#导入数据
def Importdata(datafile): dataa = pd.read_excel(datafile)  # datafile是excel文件,所以用read_excel,如果是csv文件则用read_csv#将文本中不可直接使用的文本变量替换成数字dataa['income'] = dataa['收入'].map(productDict)  # 将每一列中的数据按照字典规定的转化成数字dataa['hight'] = dataa['身高'].map(productDict)dataa['look'] = dataa['长相'].map(productDict)dataa['shape'] = dataa['体型'].map(productDict)dataa['is_meet'] = dataa['是否见面'].map(productDict)data = dataa.iloc[:,5:].values.tolist()  # 取量化后的几列,去掉文本列b = dataa.iloc[0:0,5:-1]labels = b.columns.values.tolist()  # 将标题中的值存入列表中return data,labels#计算数据的熵(entropy)--原始熵
def dataentropy(data, feat):  lendata = len(data)  # 数据条数labelCounts = {}  # 数据中不同类别的条数for featVec in data:category = featVec[-1]  # 每行数据的最后一个字(叶子节点)if category not in labelCounts.keys():labelCounts[category] = 0 labelCounts[category] += 1  # 统计有多少个类以及每个类的数量entropy = 0for key in labelCounts:prob = float(labelCounts[key]) / lendata  # 计算单个类的熵值entropy -= prob * log(prob,2)  # 累加每个类的熵值return entropy#对数据按某个特征value进行分类
def splitData(data,i,value): splitData = []for featVec in data:if featVec[i] == value:rfv = featVec[:i]rfv.extend(featVec[i+1:])splitData.append(rfv)return splitData#选择最优的分类特征
def BestSplit(data):  numFea = len(data[0]) - 1  # 计算一共有多少个特征,因为最后一列一般是分类结果,所以需要-1baseEnt = dataentropy(data, -1)  # 定义初始的熵,用于对比分类后信息增益的变化bestGainRate = 0bestFeat = -1for i in range(numFea):featList = [rowdata[i] for rowdata in data]uniqueVals = set(featList)newEnt = 0for value in uniqueVals:subData = splitData(data,i,value)  # 获取按照特征value分类后的数据prob = len(subData) / float(len(data))newEnt += prob * dataentropy(subData, i)  # 按特征分类后计算得到的熵info = baseEnt - newEnt  # 原始熵与按特征分类后的熵的差值,即信息增益splitonfo = dataentropy(subData,i)  # 分裂信息if splitonfo == 0:  # 若特征值相同(eg:长相这一特征的值都是帅),即splitonfo和info均为0,则跳过该特征continueGainRate = info / splitonfo  # 计算信息增益率if (GainRate > bestGainRate):   # 若按某特征划分后,若infoGain大于bestInf,则infoGain对应的特征分类区分样本的能力更强,更具有代表性。 bestGainRate = GainRate  # 将infoGain赋值给bestInf,如果出现比infoGain更大的信息增益,说明还有更好地特征分类bestFeat = i  # 将最大的信息增益对应的特征下标赋给bestFea,返回最佳分类特征return bestFeatdef majorityCnt(classList):    c_count = {}for i in classList:if i not in c_count.keys():c_count[i] = 0c_count[i] += 1ClassCount = sorted(c_count.items(),key=operator.itemgetter(1),reverse=True)#按照统计量降序排序return ClassCount[0][0]#reverse=True表示降序,因此取[0][0],即最大值
#构建树
def createTree(data,labels):classList = [rowdata[-1] for rowdata in data]  # 取每一行的最后一列,分类结果(1/0)if classList.count(classList[0]) == len(classList):return classList[0]if len(data[0]) == 1:return majorityCnt(classList)bestFeat = BestSplit(data)  # 根据信息增益选择最优特征bestLab = labels[bestFeat]myTree = {bestLab:{}}  # 分类结果以字典形式保存del(labels[bestFeat])featValues = [rowdata[bestFeat] for rowdata in data]uniqueVals = set(featValues)for value in uniqueVals:subLabels = labels[:]myTree[bestLab][value] = createTree(splitData(data,bestFeat,value),subLabels)return myTree#主程序
datafile = 'data/dateperson/date01.xlsx'  # 文件所在位置
data, labels = Importdata(datafile)  # 导入数据
jc=createTree(data, labels)  # 输出决策树模型结果print(jc)

得到结果和上面的算法大致差不多

PS C:\coding\machinelearning>C4.5相亲决策实验.py
{'income': {1: 1, 2: {'look': {1: 1, 2: 1, 3: {'shape': {1: {'hight': {0: 0, 1: 1}}, 3: {'hight': {0: 0, 1: 1}}}}}}, 3: {'shape': {0: 0, 1: 1}}}}
PS C:\coding\machinelearning>

CART算法

选择划分后基尼指数最小的属性最为最优划分属性。

这次我们找了个数据集,Titanic号生还者情况的数据集,来分析下乘客的生还情况

#数据处理的库
from numpy.lib.type_check import real
import pandas as pd
#数据分类
from sklearn.model_selection import train_test_split
#算法库
from sklearn.tree import DecisionTreeClassifier
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import GridSearchCV#评估用到的库
from sklearn.metrics import make_scorer
from sklearn.metrics import accuracy_score
from sklearn.metrics import f1_score
from sklearn.metrics import recall_score
from sklearn.metrics import precision_score
#预测import numpy as np#读取数据
data = pd.read_csv('data/titanic/train.csv')
print(data.head())
data.info()
# 计算各特征缺失总数
total = data.isnull().sum().sort_values(ascending=False)
# 计算各特征缺失比例
percent = (data.isnull().sum()/data.isnull().count()).sort_values(ascending = False)
miss_data = pd.concat([total, percent], axis = 1, keys = ['Miss_Total', 'Miss_Percent'])
miss_data.head()
# 缺失值处理。
# 删除‘Cabin’
del data['deck']
# 采用中位数填充缺失值
data['age'] = data['age'].fillna(data['age'].median())
# 众数填充缺失值
data['embark_town'] = data['embark_town'].fillna(data['embark_town'].mode()[0])
# 查看数据情况
data.info()# 观察Name特征提取其中的Title称呼
#data['Title'] = data['Name'].str.split(",", expand=True)[1].str.split(".", expand=True)[0]
# 将字符型变量做数值化处理
label = LabelEncoder()
data['sex'] = label.fit_transform(data['sex'])
data['class'] = label.fit_transform(data['class'])
data['alone'] = label.fit_transform(data['alone'])
#data['Embarked'] = data['Embarked'].astype(str)
data['embark_town'] = label.fit_transform(data['embark_town'])
# 考虑到PassengerId和Ticker为随机生成的变量,不作为影响目标变量的信息,因此特征选择时,将其去除
features = ['class', 'age', 'n_siblings_spouses', 'parch', 'fare', 'sex', 'alone', 'embark_town','survived']
data = data[features]
data.head()#划分训练集和测试集
X = data[['class', 'age', 'n_siblings_spouses', 'parch', 'fare', 'sex', 'alone', 'embark_town']]
y = data[['survived']]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=2)#random_state为随机种子,确保每次划分的结果是相同的#训练模型
dtc = DecisionTreeClassifier()
dtc.fit(X_train, y_train)
y_predict = dtc.predict(X_test)# 模型评分:准确率,查全率,查准率,F1得分
accuracyScore = accuracy_score(y_test, y_predict)
recallScore = recall_score(y_test, y_predict)
precisionScore = precision_score(y_test, y_predict)
f1Score = f1_score(y_test, y_predict)
print("DecisionTreeClassifier Results")
print("Accuracy      :", accuracyScore)
print("Recall        :", recallScore)
print("Precision     :", precisionScore)
print("F1 Score      :", f1Score)param = {'max_depth': [1, 3, 5, 7]}
# 采用网格搜索进行参数调优
gsearch = GridSearchCV(estimator=dtc, param_grid=param, cv=5, scoring='f1')
gsearch.fit(X=X_train, y=y_train)
print("最优参数:{}".format(gsearch.best_params_))
print("最优模型:{}".format((gsearch.best_estimator_)))
print("模型最高分:{:.3f}".format(gsearch.score(X_test, y_test)))# 选择最优模型进行预测
dtc = DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=3,max_features=None, max_leaf_nodes=None,min_samples_leaf=1, min_samples_split=2,min_weight_fraction_leaf=0.0, random_state=None,splitter='best')
dtc.fit(X_train, y_train)
y_predict = dtc.predict(X_test[:10])
# 打印预测结果
print('===================预测值=======================')
print(y_predict)
# 打印真实值
print('===================真实值=======================')
#print(np.array(y_test[:10]).tolist())
realz = np.array(y_test[:10]).ravel()
print(realz)
Accuracy = accuracy_score(realz, y_predict)
print('准确率为:{:.2f}%'.format(Accuracy*100))

打印预测结果如下:

PS C:\coding\machinelearning>CART实验(titanic).pysurvived     sex   age  n_siblings_spouses  parch     fare  class     deck  embark_town alone
0         0    male  22.0                   1      0   7.2500  Third  unknown  Southampton     n
1         1  female  38.0                   1      0  71.2833  First        C    Cherbourg     n
2         1  female  26.0                   0      0   7.9250  Third  unknown  Southampton     y
3         1  female  35.0                   1      0  53.1000  First        C  Southampton     n
4         0    male  28.0                   0      0   8.4583  Third  unknown   Queenstown     y
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 627 entries, 0 to 626
Data columns (total 10 columns):#   Column              Non-Null Count  Dtype
---  ------              --------------  -----  0   survived            627 non-null    int64  1   sex                 627 non-null    object 2   age                 627 non-null    float643   n_siblings_spouses  627 non-null    int64  4   parch               627 non-null    int64  5   fare                627 non-null    float646   class               627 non-null    object 7   deck                627 non-null    object 8   embark_town         627 non-null    object 9   alone               627 non-null    object
dtypes: float64(2), int64(3), object(5)
memory usage: 49.1+ KB
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 627 entries, 0 to 626
Data columns (total 9 columns):#   Column              Non-Null Count  Dtype
---  ------              --------------  -----0   survived            627 non-null    int641   sex                 627 non-null    object2   age                 627 non-null    float643   n_siblings_spouses  627 non-null    int644   parch               627 non-null    int645   fare                627 non-null    float646   class               627 non-null    object7   embark_town         627 non-null    object8   alone               627 non-null    object
dtypes: float64(2), int64(3), object(4)
memory usage: 44.2+ KB
DecisionTreeClassifier Results
Accuracy      : 0.7698412698412699
Recall        : 0.7142857142857143
Precision     : 0.7
F1 Score      : 0.7070707070707072
最优参数:{'max_depth': 5}
最优模型:DecisionTreeClassifier(max_depth=5)
模型最高分:0.731
===================预测值=======================
[1 1 0 1 0 0 0 1 0 0]
===================真实值=======================
[1 0 0 1 0 0 0 1 0 0]
准确率为:90.00%
PS C:\coding\machinelearning>

AI-机器学习-自学笔记(五)决策树算法相关推荐

  1. Python机器学习(三)--决策树算法

    Python机器学习(三)--决策树算法 原创  2014年07月14日 13:57:55

  2. 【机器学习】通俗的决策树算法讲解和应用

    [机器学习]通俗的决策树算法讲解和应用 文章目录 1 概述 2 决策树场景 3 决策树开发流程 4 决策树的实际运用 5 机器学习决策树算法解决图像识别-ENVI决策树分类 6 总结 1 概述 决策树 ...

  3. 【机器学习自学笔记4】朴素贝叶斯分类器

    title: [机器学习自学笔记4]朴素贝叶斯分类器 date: 2020-10-29 18:34:29 categories: 机器学习 tags: 机器学习 概率论 贝叶斯分类是一类分类算法的总称 ...

  4. Python3:《机器学习实战》之决策树算法(3)预测隐形眼镜类型

    Python3:<机器学习实战>之决策树算法(3)预测隐形眼镜类型 转载请注明作者和出处:http://blog.csdn.net/u011475210 代码地址:https://gith ...

  5. 基于 Java 机器学习自学笔记 (第61-62天:ID3决策树)

    注意:本篇为50天后的Java自学笔记扩充,内容不再是基础数据结构内容而是机器学习中的各种经典算法.这部分博客更侧重于笔记以方便自己的理解,自我知识的输出明显减少,若有错误欢迎指正! 目录 一.关于决 ...

  6. 基于 Java 机器学习自学笔记 (第63-65天:集成学习之AdaBoost)

    注意:本篇为50天后的Java自学笔记扩充,内容不再是基础数据结构内容而是机器学习中的各种经典算法.这部分博客更侧重于笔记以方便自己的理解,自我知识的输出明显减少,若有错误欢迎指正! 目录 一.关于集 ...

  7. 【机器学习入门】(5) 决策树算法实战:sklearn实现决策树,实例应用(沉船幸存者预测)附python完整代码及数据集

    各位同学好,今天和大家分享一下python机器学习中的决策树算法,在上一节中我介绍了决策树算法的基本原理,这一节,我将通过实例应用带大家进一步认识这个算法.文末有完整代码和数据集,需要的自取.那我们开 ...

  8. 【机器学习入门】(4) 决策树算法理论:算法原理、信息熵、信息增益、预剪枝、后剪枝、算法选择

    各位同学好,今天我向大家介绍一下python机器学习中的决策树算法的基本原理.内容主要有: (1) 概念理解:(2) 信息熵:(3) 信息增益:(4) 算法选择:(5) 预剪枝和后剪枝. python ...

  9. 决策树 prepruning_智能建筑运维前探 AI天天见之五:决策树算法应用探索

    点击上方"蓝字"关注我们,成为幸福的人~ 这是一个大街小巷热议人工智能的时代~ 人工智能犹如上世纪九十年代的互联网,以惊涛之势席卷大江南北.带动着产业革命. 作为智慧建筑运维领域的 ...

  10. 基于Java机器学习自学笔记(第81-87天:CNN卷积神经网络的入门到全代码编写)

    注意:本篇为50天后的Java自学笔记扩充,内容不再是基础数据结构内容而是机器学习中的各种经典算法.这部分博客更侧重于笔记以方便自己的理解,自我知识的输出明显减少,若有错误欢迎指正! 目录 1. CN ...

最新文章

  1. Java反射中method.isBridge() 桥接方法
  2. @autowired注解_SpringBoot常用注解大全
  3. Linux下编译vtk的java版本,Ubuntu 16.04 编译VTK7.1
  4. C++进程数量的限制
  5. php 中数组的定义赋值吗,怎么在php中定义一个数组
  6. vim中如何设置多行注释和删除注释
  7. 六步带你完成博流wifi模组对接华为云流程
  8. 天猫国际宣布今年要孵化1000家“数字化首店”
  9. Python + ElasticSearch:有了这个超级武器,你也可以报名参加诗词大会了!
  10. java梯形_如何绘制梯形?
  11. 电信网编号计划征求意见 物联网产业有望迎来风口
  12. Hadoop/Spark集群搭建图文全攻略
  13. 文字识别(四)--大批量生成文字训练集
  14. Laravel本地Sail开发环境下Phpstorm+浏览器+Postman调试配置
  15. vue开发项目必备知识
  16. SpringBoot学生成绩管理系统
  17. AD17开发流程和经验技巧
  18. sae项目服务器,sae服务器 mysql数据库
  19. Barsetto百胜图BAC731B智能胶囊咖啡机测评,醇香相伴随性生活
  20. 计算机专业认知实践报告1000,计算机专业实习报告1000字

热门文章

  1. 手拉手-富春山居千人微商群星峰会 到场人数爆棚
  2. 非计算机转后台开发并入职字节跳动(四)--再回业务后台开发,头条工作体验
  3. 江民在线杀毒的用户名和密码
  4. 跨平台应用开发进阶(八) :uni-app 实现Android原生APP-云打包集成极光推送(JG-JPUSH)详细教程
  5. Excel VBA 多重筛选
  6. 如何进入电商直播行业?直播平台有哪些选择?
  7. 您找不到工作的原因可能在这里?
  8. Word中NoteExpress不显示的问题
  9. 什么是ROC与AUC以及如何使用
  10. blender怎样给平面或曲面自动贴图