决策树算法简介
决策树定义
决策树算法是一种基于树状结构的分类和回归方法,它通过对数据集进行递归地划分,构建一棵树来实现对数据的分类或预测。在决策树中,每个内部节点表示对特征的判断,每个叶节点表示最终的分类或回归结果。决策树的构建过程包括特征选择、树的构建、决策规则的生成以及剪枝等步骤。
决策树算法的基本思想是通过对特征的逐步划分,将数据集划分为不同的类别或者回归值,使得同一类别内的数据尽可能相似,不同类别之间的差异尽可能大。决策树的构建过程中,通过选择合适的特征和划分点,使得每一步划分都能最大程度地提高分类或回归的准确性。最终得到的决策树模型可以用于对新样本进行分类或者回归预测。
决策树算法具有简单易懂、模型具有可解释性等优点,在实际应用中被广泛使用。常见的决策树算法包括ID3、C4.5、CART等。
优缺点
优点:
1.易于理解和解释:生成的决策树模型具有直观的可解释性,可以清晰地展示特征之间的关系,便于理解和解释,适合用于决策支持系统。
2.处理混合数据类型:决策树算法可以处理离散型和连续型特征,以及多类别分类问题,不需要对数据进行特殊处理。
3.计算成本低:在训练阶段,决策树的构建过程相对简单,计算成本较低,适用于处理大规模数据集。
4.能够处理多输出问题:决策树算法可以自然地扩展到多输出任务,例如多标签分类和回归问题。
5.对缺失值不敏感:决策树算法对缺失值的处理能力较强,能够处理数据中的缺失值。
缺点:
1.容易过拟合:决策树算法在处理复杂数据时容易过拟合,特别是在训练数据量较小、树的深度较大、特征数量较多时,需要进行适当的剪枝操作来降低模型的复杂度,防止过拟合。
2.不稳定性:数据的微小变化可能导致生成的决策树结构发生较大变化,即决策树模型的稳定性较差。
3.不能处理连续性特征:原始的决策树算法不能直接处理连续型特征,需要通过离散化或其他方法进行处理。
4.忽略特征之间的相关性:决策树算法基于单个特征的信息进行划分,忽略了特征之间的相关性,可能导致模型学习到不准确的决策规则。
5.不适合处理高维稀疏数据:当特征数量较多、特征空间较大时,决策树的效果可能不佳,容易产生过拟合现象。
总结
决策树算法简单易懂,且生成的模型具有可解释性,适用于处理离散型和连续型数据,并且能够处理大规模数据集。然而,决策树算法也有一些缺点,比如对噪声和异常值敏感,容易产生过拟合问题,需要进行适当的剪枝操作。
决策树算法工作原理
决策树算法的工作原理基于对数据集进行递归的二分或多分,通过特征的划分来构建一棵树,实现对数据的分类或预测。
特征选择:选择最优的特征用于数据划分。通常根据某种指标(如信息增益、信息增益率、基尼系数等)来选择对分类或回归任务最具有区分性的特征作为划分依据。
树的构建:从根节点开始,根据选定的特征对数据集进行划分,生成子节点。每个子节点代表了一个特征值或特征组合,并且对应着一个决策规则。重复上述过程,对每个子节点继续进行特征选择和数据划分,直到满足停止条件。停止条件可以是节点中样本数量小于某个阈值、节点的深度达到预设的最大深度、或者节点中的样本属于同一类别等。
决策规则:决策树的每个内部节点表示对特征的判断,根据判断结果将数据划分到不同的子节点。叶节点表示最终的分类或回归结果。当样本到达叶节点时,根据叶节点的分类或回归结果进行预测或分类。
剪枝:为了防止过拟合,需要对构建好的决策树进行剪枝操作。剪枝可以分为预剪枝和后剪枝两种方式,其中预剪枝是在树的构建过程中进行判断是否分裂节点,后剪枝是在树构建完成后通过剪掉部分节点来减小树的复杂度。
预测与分类:对于新样本的预测或分类,通过将样本从根节点开始沿着树的路径进行判断,最终到达叶节点,根据叶节点的分类结果来进行预测或分类。
特征选择方法
信息增益
信息增益是决策树算法中用于选择最优特征进行数据划分的一种指标,它衡量了使用某个特征对数据进行划分后所能带来的信息量的增加。信息增益的计算基于信息论中的熵(Entropy)概念,它表示了数据集的不确定性或混乱程度。
假设有一个数据集 D,包含 N 个样本,其中第 i 个样本属于类别 Ci, i=1,2,...,n, ∣Ci∣ 表示类别 Ci 中样本的数量。如果将数据集 D划分为 m 个子集 D1,D2,...,Dm,对应于特征 A 的不同取值,每个子集中包含的样本数量分别为 ∣D1∣,∣D2∣,...,∣Dm∣,则特征 A 的信息增益Gain(A) 定义为:
其中,Entropy(D) 是数据集 D 的熵,Entropy(Di) 是子集 Di 的熵。
信息增益越大,表示使用特征 A 进行数据划分后,数据集的不确定性减少得越多,因此特征 A 更具有区分性。
信息增益率
信息增益率是决策树算法中用于选择最优特征进行数据划分的一种指标,它是信息增益除以划分数据集之后的熵(Entropy)的比值。信息增益率考虑了特征的取值数目对信息增益的影响,对于取值数目较多的特征会进行一定程度的惩罚,以防止过度选择取值数目较多的特征。
假设有一个数据集 D,包含 N个样本,其中第 i个样本属于类别 Ci, i=1,2,...,n, ∣Ci∣ 表示类别 Ci 中样本的数量。如果将数据集 D 划分为 m 个子集 D1,D2,...,Dm,对应于特征 A 的不同取值,每个子集中包含的样本数量分别为 ∣D1∣,∣D2∣,...,∣Dm∣,则特征 A 的信息增益率 Gain_Ratio(A) 定义为
其中,Gain(A)是特征 A 的信息增益, Split_Info(A) 是特征 A 的分裂信息,表示对数据集 D 进行特征 A 划分后的熵。
信息增益率越大,表示使用特征 AA 进行数据划分后,除了减少数据集的不确定性之外,还考虑了特征取值数目对信息增益的影响。
基尼指数
基尼指数(Gini Index)是决策树算法中用于选择最优特征进行数据划分的一种指标,它衡量了从数据集中随机选择两个样本,其类别不一致的概率。基尼指数越小,表示数据集的不纯度越低,特征的区分能力越好,因此是选择最优特征的一个重要指标之一。
假设有一个数据集 D,包含 N 个样本,其中第 i 个样本属于类别 Ci, i=1,2,...,n, ∣Ci∣∣Ci∣ 表示类别 Ci 中样本的数量。如果将数据集 D 划分为 m 个子集 D1,D2,...,Dm,对应于特征 A 的不同取值,每个子集中包含的样本数量分别为 ∣D1∣,∣D2∣,...,∣Dm∣,则特征 A 的基尼指数 Gini(A)) 定义为:
基尼指数越小,表示特征 AA 的划分越纯净,即样本属于同一类别的概率越大。因此,基尼指数可以作为一种衡量数据集不纯度的指标,用于选择最优的划分特征。
在决策树的构建过程中,通常选择基尼指数最小的特征作为最优划分特征,以实现对数据集的最优划分。
决策树具体实例
隐形眼镜数据集是非常著名的数据集,它包含很多换着眼部状态的观察条件以及医生推荐的隐形眼镜类型。隐形眼镜类型包括硬材质(hard)、软材质(soft)以及不适合佩戴隐形眼镜(no lenses)。
一共有24组数据,数据的Labels依次是age
、prescript
、astigmatic
、tearRate
、class
,也就是第一列是年龄,第二列是症状,第三列是是否散光,第四列是眼泪数量,第五列是最终的分类标签。数据如下图所示:
使用Sklearn构建决策树
由于fit()函数不能接收string
类型的数据,所以在使用fit()函数之前,我们需要对数据集进行编码,为了对string
类型的数据序列化,需要先生成pandas数据,这样方便我们的序列化工作。这里我参考使用的方法是,原始数据->字典->pandas数据,代码如下
# -*- coding: UTF-8 -*-
import pandas as pd
if __name__ == '__main__':
with open(r'C:\Users\24527\Desktop\机器学习\lenses.txt', 'r') as fr: #加载文件
lenses = [inst.strip().split('\t') for inst in fr.readlines()] #处理文件
lenses_target = [] #提取每组数据的类别,保存在列表里
for each in lenses:
lenses_target.append(each[-1])
lensesLabels = ['age', 'prescript', 'astigmatic', 'tearRate'] #特征标签
lenses_list = [] #保存lenses数据的临时列表
lenses_dict = {} #保存lenses数据的字典,用于生成pandas
for each_label in lensesLabels: #提取信息,生成字典
for each in lenses:
lenses_list.append(each[lensesLabels.index(each_label)])
lenses_dict[each_label] = lenses_list
lenses_list = []
print(lenses_dict) #打印字典信息
lenses_pd = pd.DataFrame(lenses_dict) #生成pandas.DataFrame
print(lenses_pd)
顺利生成pandas数据
接下来,我们需要将数据序列化,代码如下
import pydotplus
import pandas as pd
from sklearn.preprocessing import LabelEncoder
import six
if __name__ == '__main__':
with open(r'C:\Users\24527\Desktop\机器学习\lenses.txt', 'r') as fr:
lenses = [inst.strip().split('\t') for inst in fr.readlines()]
lenses_target = []
for each in lenses:
lenses_target.append(each[-1])
lensesLabels = ['age', 'prescript', 'astigmatic', 'tearRate']
lenses_dict = {}
for each_label in lensesLabels:
lenses_list = []
for each in lenses:
lenses_list.append(each[lensesLabels.index(each_label)])
lenses_dict[each_label] = lenses_list
lenses_pd = pd.DataFrame(lenses_dict)
print(lenses_pd)
le = LabelEncoder()
for col in lenses_pd.columns:
lenses_pd[col] = le.fit_transform(lenses_pd[col])
print(lenses_pd)
接下来我们编写代码绘制决策树
# -*- coding: UTF-8 -*-
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
from six import StringIO
from sklearn import tree
import pandas as pd
import numpy as np
import os
os.environ["PATH"] += os.pathsep + 'C:/Program Files/Graphviz/bin' # 指定 Graphviz 的安装路径
import pydotplus
if __name__ == '__main__':
with open(r'C:\Users\24527\Desktop\机器学习\lenses.txt', 'r') as fr: #加载文件
lenses = [inst.strip().split('\t') for inst in fr.readlines()] #处理文件
lenses_target = [] #提取每组数据的类别,保存在列表里
for each in lenses:
lenses_target.append(each[-1])
print(lenses_target)
lensesLabels = ['age', 'prescript', 'astigmatic', 'tearRate'] #特征标签
lenses_list = [] #保存lenses数据的临时列表
lenses_dict = {} #保存lenses数据的字典,用于生成pandas
for each_label in lensesLabels: #提取信息,生成字典
for each in lenses:
lenses_list.append(each[lensesLabels.index(each_label)])
lenses_dict[each_label] = lenses_list
lenses_list = []
# print(lenses_dict) #打印字典信息
lenses_pd = pd.DataFrame(lenses_dict) #生成pandas.DataFrame
# print(lenses_pd) #打印pandas.DataFrame
le = LabelEncoder() #创建LabelEncoder()对象,用于序列化
for col in lenses_pd.columns: #序列化
lenses_pd[col] = le.fit_transform(lenses_pd[col])
# print(lenses_pd) #打印编码信息
clf = tree.DecisionTreeClassifier(max_depth = 4) #创建DecisionTreeClassifier()类
clf = clf.fit(lenses_pd.values.tolist(), lenses_target) #使用数据,构建决策树
dot_data = StringIO()
tree.export_graphviz(clf, out_file = dot_data, #绘制决策树
feature_names = lenses_pd.keys(),
class_names = clf.classes_,
filled=True, rounded=True,
special_characters=True)
graph = pydotplus.graph_from_dot_data(dot_data.getvalue())
graph.write_pdf("tree.pdf") #保存绘制好的决策树,以PDF的形式存储。
下图为此实验运行之后生成的决策树
决策树绘制好之后,输入一个测试集来进行预测
print(clf.predict([[1,1,1,0]])) #预测
结果如下