一、决策树的概述
决策树是一种树形结构,其中每个内部节点表示一个属性上的测试,每个分支代表一个测试输出,每个叶子节点代表一种类别。树的组成:(如下图示,来源百度,只做结构演示说明)
根节点:第一个选择点
非叶子结点与分支:中间过程
叶子节点:最终的决策结果
决策树是一树状结构,它的每一个叶节点对应着一个分类,非叶节点对应着在某个属性上的划分,根据样本在该属性上的不同取值将其划分成若干个子集。对于非纯的叶节点,多数类的标号给出到达这个节点的样本所属的类。构造决策树的核心问题是在每一步如何选择适当的属性对样本做拆分。对一个分类问题,从已知类标记的训练样本中学习并构造出决策树是一个自上而下,分而治之的过程。
二、决策树的优缺点:
优点
1.易于理解和解释。由于决策树模型基于树形结构,因此可以直观地展示特征属性之间的关系,易于解释。
2.适用于多种类型的数据。决策树模型可以处理分类、回归等不同类型的数据。
3.能够处理非线性关系。与线性模型不同,决策树模型可以处理非线性关系,适用于复杂的问题。
缺点:
1.容易过拟合。当决策树过于复杂时,容易出现过拟合现象,影响模型的泛化能力。
2.对噪声敏感。样本数据中存在异常值或噪声时,会影响决策树的划分效果。
3.不稳定。当样本数据发生变化时,决策树模型可能会发生较大的变化,导致模型不稳定。
应用场景:
1.分类问题。对于多分类问题,决策树模型可以构建一棵多叉树,每个叶子节点代表一个类别。
2.回归问题。对于连续型变量的预测问题,决策树模型可以构建一棵回归树,每个叶子节点代表一个预测值。
3.特征选择。通过分析决策树模型的划分过程,可以确定哪些特征属性对分类或回归具有更大的贡献。
4.集成学习。决策树模型可以与其他模型进行集成学习,如随机森林、梯度提升树等。
决策树的结构
决策树是一种基于树形结构进行决策分析的模型,其结构由节点和边组成。
根节点:根节点位于决策树的最顶层,代表整个样本集合,并根据某个特征属性进行分裂,形成若干个子节点。
内部节点:内部节点代表一个特征属性,它分裂出若干个子节点,对应着该属性的不同取值。
叶节点:叶节点代表分类或回归的结果,没有子节点。
分支:分支使得节点相互连接,表示不同的分支条件。
深度:从根节点到叶节点的路径长度称为深度。
三、决策树实际应用:
#数据加载
def loadData( ):
data = pd.read_csv("titanic.csv")
data["Age"] = data["Age"].fillna(data["Age"].mean()) #针对Age字段,采用均值进行填充
data = data.dropna()
data.isna().sum()
dataset = data.values.tolist()
#四个属性
labels=['Pclass','Age','Sex','Survived']
return dataset,labels
#计算给定数据的香农熵
def calShannonEnt(dataset):
numEntries = len(dataset) #获得数据集函数
labelCounts={} #用于保存每个标签出现的次数
for data in dataset:
#提取标签信息
classlabel = data[-1]
if(classlabel not in labelCounts.keys()): #如果标签未放入统计次数的字典,则添加进去
labelCounts[classlabel]=0
labelCounts[classlabel]+=1 #标签计数
shannonEnt=0.0 #熵初始化
for key in labelCounts:
p = float(labelCounts[key])/numEntries #选择该标签的概率
shannonEnt-= p*np.log2(p)
return shannonEnt #返回经验熵
#根据某一特征划分数据集
def splitDataset(dataset,axis,value):
# dataset 待划分的数据集 axis 划分数据集的特征 value 返回数据属性值为value
retDataSet = [] #创建新的list对象
for featVec in dataset: #遍历元素
if featVec[axis]==value: #符合条件的抽取出来
reducedFeatVec = featVec[:axis]
reducedFeatVec.extend(featVec[axis+1:])
retDataSet.append(reducedFeatVec)
return retDataSet
# 统计出现次数最多的元素(类标签)
def majorityCnt(classList):
classCount={} #统计classList中每个类标签出现的次数
for vote in classList:
if vote not in classCount.keys():
classCount[vote] = 0
classCount[vote] += 1
sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True) #根据字典的值降序排列
return sortedClassCount[0][0] #返回出现次数最多的类标签
def createTree(dataset,labels):#数据集和标签列表
classList =[example[-1] for example in dataset]#数据所属类得值
if classList.count(classList[0])==len(classList):#条件1:classList只剩下一种值
return classList[0]
if len(dataset[0])==1:#条件2:数据dataset中属性已使用完毕,但没有分配完毕
return majorityCnt(classList)#取数量多的作为分类
bestFeat = chooseBestFeatureToSplit(dataset)#选择最好的分类点,即香农熵值最小的
labels2 = labels.copy()#复制一分labels值,防止原数据被修改。
bestFeatLabel = labels2[bestFeat]
myTree = {bestFeatLabel:{}}#选取获取的最好的属性作为
del(labels2[bestFeat])
featValues = [example[bestFeat] for example in dataset]#获取该属性下的几类值
uniqueVals = set(featValues)
for value in uniqueVals:
subLabels = labels2[:]#剩余属性列表
myTree[bestFeatLabel][value] = createTree(splitDataset(dataset,bestFeat,value),subLabels)
return myTree
if __name__ == '__main__':
dataSet, labels = loadData( )
print("数据集信息熵:"+str(calShannonEnt(dataSet)))
mytree = createTree(dataSet,labels)
print(mytree)
绘制:
import numpy as np
import pandas as pd
from sklearn import tree
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.feature_extraction import DictVectorizer
from sklearn.tree import export_graphviz
import matplotlib.pyplot as plt
# 加载数据
data = pd.read_csv('titanic.csv')
# print(data.head())
# print(data.shape) # (891, 12)
# 获取数据
x = data[['Pclass','Age','Sex']]
y = data['Survived']
# print(x.head())
# print(y.head())
# 缺失值处理
x['Age'].fillna(x['Age'].mean(),inplace=True)
# 特征处理
x['Sex'] = np.array([0 if i == 'male' else 1 for i in x['Sex']]).T
# 打印查看是否替换成功
# print(x.head())
# 划分数据集
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2,random_state=22)
# 创建模型
model = DecisionTreeClassifier(criterion='entropy',max_depth=3)
# 3 准确率: 0.7653631284916201
# 4 准确率: 0.7653631284916201
# 5 准确率: 0.7430167597765364
# 6 准确率: 0.7486033519553073
# 8 准确率: 0.7541899441340782
# 12 准确率: 0.770949720670391
model.fit(x_train,y_train)
# 评估
score = model.score(x_test,y_test)
pred = model.predict(x_test)
print('准确率:',score)
print('预测值:',pred)
# 可视化方法一:
# export_graphviz(model, out_file="tree.dot", feature_names=['pclass','age','sex'])
# 更简单的方法:
plt.figure(figsize=(20,20))
feature_name = ['pclass','age','sex']
class_name = ['survived','death']
tree.plot_tree(model,feature_names=feature_name,class_names=class_name)
plt.savefig('tree.png')
四、总结:
本文详细介绍了决策树的理论基础,包括最优属性选择的三种方法,并通过Python代码展示了如何使用scikit-learn库创建决策树、评估模型性能并进行可视化。在实际应用中,我们可以根据数据的特点和需求选择合适的最优属性选择方法。这次实验也让我对决策树有了更深的理解和看法,重点就是掌握决策树的决策理论以及最优属性的选择方法,实验过程中我也遇到了很多困难,比如对Python不熟悉对scikit-learn库中的函数不熟悉。最后,希望在之后的机器学习之旅我能更上一层楼,期待下一次机器学习算法实验。