AI-机器学习-自学笔记(五)决策树算法
决策树(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-机器学习-自学笔记(五)决策树算法相关推荐
- Python机器学习(三)--决策树算法
Python机器学习(三)--决策树算法 原创 2014年07月14日 13:57:55
- 【机器学习】通俗的决策树算法讲解和应用
[机器学习]通俗的决策树算法讲解和应用 文章目录 1 概述 2 决策树场景 3 决策树开发流程 4 决策树的实际运用 5 机器学习决策树算法解决图像识别-ENVI决策树分类 6 总结 1 概述 决策树 ...
- 【机器学习自学笔记4】朴素贝叶斯分类器
title: [机器学习自学笔记4]朴素贝叶斯分类器 date: 2020-10-29 18:34:29 categories: 机器学习 tags: 机器学习 概率论 贝叶斯分类是一类分类算法的总称 ...
- Python3:《机器学习实战》之决策树算法(3)预测隐形眼镜类型
Python3:<机器学习实战>之决策树算法(3)预测隐形眼镜类型 转载请注明作者和出处:http://blog.csdn.net/u011475210 代码地址:https://gith ...
- 基于 Java 机器学习自学笔记 (第61-62天:ID3决策树)
注意:本篇为50天后的Java自学笔记扩充,内容不再是基础数据结构内容而是机器学习中的各种经典算法.这部分博客更侧重于笔记以方便自己的理解,自我知识的输出明显减少,若有错误欢迎指正! 目录 一.关于决 ...
- 基于 Java 机器学习自学笔记 (第63-65天:集成学习之AdaBoost)
注意:本篇为50天后的Java自学笔记扩充,内容不再是基础数据结构内容而是机器学习中的各种经典算法.这部分博客更侧重于笔记以方便自己的理解,自我知识的输出明显减少,若有错误欢迎指正! 目录 一.关于集 ...
- 【机器学习入门】(5) 决策树算法实战:sklearn实现决策树,实例应用(沉船幸存者预测)附python完整代码及数据集
各位同学好,今天和大家分享一下python机器学习中的决策树算法,在上一节中我介绍了决策树算法的基本原理,这一节,我将通过实例应用带大家进一步认识这个算法.文末有完整代码和数据集,需要的自取.那我们开 ...
- 【机器学习入门】(4) 决策树算法理论:算法原理、信息熵、信息增益、预剪枝、后剪枝、算法选择
各位同学好,今天我向大家介绍一下python机器学习中的决策树算法的基本原理.内容主要有: (1) 概念理解:(2) 信息熵:(3) 信息增益:(4) 算法选择:(5) 预剪枝和后剪枝. python ...
- 决策树 prepruning_智能建筑运维前探 AI天天见之五:决策树算法应用探索
点击上方"蓝字"关注我们,成为幸福的人~ 这是一个大街小巷热议人工智能的时代~ 人工智能犹如上世纪九十年代的互联网,以惊涛之势席卷大江南北.带动着产业革命. 作为智慧建筑运维领域的 ...
- 基于Java机器学习自学笔记(第81-87天:CNN卷积神经网络的入门到全代码编写)
注意:本篇为50天后的Java自学笔记扩充,内容不再是基础数据结构内容而是机器学习中的各种经典算法.这部分博客更侧重于笔记以方便自己的理解,自我知识的输出明显减少,若有错误欢迎指正! 目录 1. CN ...
最新文章
- Java反射中method.isBridge() 桥接方法
- @autowired注解_SpringBoot常用注解大全
- Linux下编译vtk的java版本,Ubuntu 16.04 编译VTK7.1
- C++进程数量的限制
- php 中数组的定义赋值吗,怎么在php中定义一个数组
- vim中如何设置多行注释和删除注释
- 六步带你完成博流wifi模组对接华为云流程
- 天猫国际宣布今年要孵化1000家“数字化首店”
- Python + ElasticSearch:有了这个超级武器,你也可以报名参加诗词大会了!
- java梯形_如何绘制梯形?
- 电信网编号计划征求意见 物联网产业有望迎来风口
- Hadoop/Spark集群搭建图文全攻略
- 文字识别(四)--大批量生成文字训练集
- Laravel本地Sail开发环境下Phpstorm+浏览器+Postman调试配置
- vue开发项目必备知识
- SpringBoot学生成绩管理系统
- AD17开发流程和经验技巧
- sae项目服务器,sae服务器 mysql数据库
- Barsetto百胜图BAC731B智能胶囊咖啡机测评,醇香相伴随性生活
- 计算机专业认知实践报告1000,计算机专业实习报告1000字