机器学习之决策树(python 您所在的位置:网站首页 clf是什么意思 机器学习之决策树(python

机器学习之决策树(python

2023-03-23 00:42| 来源: 网络整理| 查看: 265

1.sklearn中的决策树 模块sklearn.tree(scikit-learn)

sklearn中决策树的类都在”tree“这个模块之下。这个模块总共包含五个类:

tree.DecisionTreeClassifier 分类树 tree.DecisionTreeRegressor 回归树 tree.export_graphviz 将生成的决策树导出为DOT格式,画图专用 tree.ExtraTreeClassifier 高随机版本的分类树 tree.ExtraTreeRegressor 高随机版本的回归树

sklearn建模的基本流程:

image-20230316161926873

在这个流程下,对应的代码为:

from sklearn import tree #导入需要的模块 clf = tree.DecisionTreeClassifier()     #实例化 clf = clf.fit(X_train,y_train) #用训练集数据训练模型 result = clf.score(X_test,y_test) #导入测试集,从接口中调用需要的信息 2.DecisionTreeClassifier

classsklearn.tree.DecisionTreeClassifier(criterion=’gini’, splitter=’best’, max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=None, random_state=None,max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, class_weight=None, presort=False)

2.1重要参数 2.1.1criterion

Criterion这个参数是决定决策树不纯度的计算方式的。

sklearn提供了两种方式:

输入”entropy“,使用信息熵(Entropy) 输入”gini“,使用基尼系数(Gini Impurity)

二者有什么区别呢?

比起基尼系数,信息熵对不纯度更加敏感,对不纯度的惩罚最强。但是在实际使用中,信息熵和基尼系数的效果基 本相同。信息熵的计算比基尼系数缓慢一些,因为基尼系数的计算不涉及对数。另外,因为信息熵对不纯度更加敏 感,所以信息熵作为指标时,决策树的生长会更加“精细”,因此对于高维数据或者噪音很多的数据,信息熵很容易 过拟合,基尼系数在这种情况下效果往往比较好。当然,这不是绝对的。 信息熵其实算的是信息增益(也就是父节点和子节点的信息熵的差值,然后寻找使得差值最大的分类指标) 信息熵:$$Ent\left( D \right) =-\sum_{k=1}^{|y|}{p_k\log _2p_k} $$ 假定当前样本集合D中第k类样本所占的比例为\(p_k(k=1,2,...|y|)\) Ent(D)的值越小,则D的纯度越大 Ent(D)的最小值为0,最大值为\(log_2|y|\) y表示标签的种类 信息熵越小,不确定越小,已知的信息越多,树节点的纯度越大(熵是指变化,熵越大,说明不确定性越大,则已知信息越小) 离散属性a有V个可能的取值{\({a^1,a^2,...,a^n}\)},用a来进行划分,则会产生V个分支结点,其中第v个分支结点包含了所有在属性上取值为\(a^v\)的样本,记为\(D^v\)。则可计算出用属性a对样本集D进行划分所获得的“信息增益”:

\[Gain\left( D,a \right) =Ent\left( D \right) -\sum_{v=1}^V{\frac{|D^v|}{|D|}Ent\left( D^v \right)} \]

注意:信息增益倾向于选择产生大量小而纯的子集的分裂方案。用一个极端的例子来说明:当数据集的某个属性对于每一个实例存在一个不同属性值时,比如,一个标志码属性,按照信息增益值计算会被选择为分裂属性,但显然这是不合适的,因为ID属性对测试集中的分类是无益的。 参数 criterion 如何影响模型? 确定不纯度的计算方法,帮忙找出最佳节点和最佳分枝,不纯度越低,决策树对训练集的拟合越好 可能的输入有哪些? 不填默认基尼系数,填写gini使用基尼系数,填写entropy使用信息增益 怎样选取参数? 通常就使用基尼系数;数据维度很大,噪音很大时使用基尼系数;维度低,数据比较清晰的时候,信息熵和基尼系数没区别;当决策树的拟合程度不够的时候,使用信息熵;两个都试试,不好就换另外一个

[*zip(x,y)]这段代码什么意思?

这段代码是用来将两个列表 x 和 y 中的元素配对并返回一个新的列表。每个元素都是一个元组,其中第一个元素来自 x,第二个元素来自 y。例如:

x = [1, 2, 3] y = ['a', 'b', 'c'] result = [*zip(x,y)] print(result)

输出结果为:[(1, 'a'), (2, 'b'), (3, 'c')]

建立一颗树:

1.导入需要的算法库和模块

# 导入算法库和模块 from sklearn import tree from sklearn.datasets import load_wine # 数据集,红酒数据 from sklearn.model_selection import train_test_split # 划分训练集和测试集

2.探索数据

wine = load_wine() wine image-20230317100233438 image-20230317100301012

合并数据和标签,形成一个表:

pd.concat([pd.DataFrame(wine.data), pd.DataFrame(wine.target,columns=['target'])], axis=1) axis=1表示按行索引合并 wine.feature_names # 属性名 wine.target_names # 标签名

3.训练集和测试集划分:

Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data, wine.target, test_size=0.3) # 这个train_test_split()函数有三个参数 #分别表示数据、标签、测试集和训练集比例 #0.3表示70%的训练集,30%的测试集,这里是随机划分的 #后面可以设置一个random_state参数,即设置一个随机数种子,使得划分固定

4.模型建立

clf = tree.DecisionTreeClassifier(criterion='entropy') clf = clf.fit(Xtrain, Ytrain) # 模型训练 score = clf.score(Xtest, Ytest) # 返回模型精确度,accuracy

5.绘制决策树

feature_name = ['酒精','苹果酸','灰','灰的碱性','镁','总酚','类黄酮','非黄烷类酚类','花青素','颜色强度','色调','od280/od315稀释葡萄酒','脯氨酸'] import graphviz dot_data = tree.export_graphviz(clf ,feature_names= feature_name ,class_names=['琴酒', '雪莉', '贝尔摩德'] ,filled=True ,rounded=True) graph = graphviz.Source(dot_data) graph

决策树1

6.探索决策树

[*zip(feature_name,clf.feature_importances_)]

image-20230317102651230

这里可以用于判断不同的变量在决策过程中的重要性。(变量重要性)

2.1.2random_state & splitter clf = tree.DecisionTreeClassifier(criterion="entropy",random_state=30) # 这里的random_state可以使score保持稳定 clf = clf.fit(Xtrain, Ytrain) score = clf.score(Xtest, Ytest) #返回预测的准确度 score

上述代码和之前的模型构建部分有一点不同,在于设置了random_state这个参数。

那个这个参数有什么用呢?

使用new bing回答这个问题:

问1:sklearn中random_state参数有什么用?

答1:sklearn中的random_state参数是用来控制随机性的。它可以是一个整数,一个RandomState实例或者None。如果是一个整数,它就是一个随机种子,可以使得多次函数调用产生相同的随机结果。如果是None,它就使用np.random的默认RandomState实例。如果是一个RandomState实例,它就直接使用该实例生成随机数。

问2:random_state参数对模型性能有什么影响?

答2:根据搜索结果,random_state参数对模型性能有一定的影响,因为它决定了数据的随机性。不同的随机性可能导致不同的模型结果,例如聚类模型中的簇数。但是,random_state参数并不是一个需要调优的超参数,因为它只影响模型在特定数据集上的表现,而不是模型本身的泛化能力。如果想要保证多次运行模型或者划分数据时得到相同的结果,可以指定一个固定的random_state值。

问3:那么如何选择一个合适的random_state值呢?

答3:选择一个合适的random_state值并没有一个固定的规则,只要保证每次运行代码时使用相同的值就可以了。这样可以确保数据的划分或者模型的训练是可重复的。一般来说,可以使用任意一个整数作为random_state值,例如0或者42,或者使用默认的None。但是如果想要比较不同模型或者参数的效果,最好固定一个random_state值。

总结:random_state是便于多次训练得到同一棵树,防止模型无法复现,比如决策树分枝的时候,如果多个特征的不纯度一样,使用这个随机数就可以保证随机每次选取的划分特征是一样的,再例如一些连续特征,计算分割点就需要随机,模型需要复现,就要保证这个随机性每次都一样。

比如说如果像前面那样没有设置random_state参数,多次重复运行代码,得到的score值可能会不同。

可以运行下面这段代码验证:

score_cmp = [] for i in range(100): clf = tree.DecisionTreeClassifier(criterion='entropy') clf = clf.fit(Xtrain, Ytrain) # 模型训练 score = clf.score(Xtest, Ytest) # 返回模型精确度,accuracy score_cmp.append(score) plt.figure(dpi=200) plt.plot(range(100), score_cmp, 'r-') plt.show() image-20230317111607371 可以看出重复运行100次,得到的score的值会不同 score_cmp = [] for i in range(100): clf = tree.DecisionTreeClassifier(criterion='entropy', random_state=30) clf = clf.fit(Xtrain, Ytrain) # 模型训练 score = clf.score(Xtest, Ytest) # 返回模型精确度,accuracy score_cmp.append(score) plt.figure(dpi=200) plt.plot(range(100), score_cmp, 'r-') plt.show() image-20230317112505943 可以看出增加了random_state参数后,即使重复运行代码100遍,得到的score始终保持不变

至于splitter参数:

splitter参数对模型的影响主要体现在分枝时的随机性和效率上。如果设置为'best',则决策树会优先选择更重要(按照不纯度设置的基尼系数或者信息熵的值)的特征进行分枝,这样可以得到更准确和更简洁的决策树,但是计算量也会更大。如果设置为'random',则决策树会更加随机地选择特征进行分枝,这样可以增加模型的多样性和鲁棒性,但是可能会降低模型的准确性和可解释性。 你可以根据你的数据集和目标来选择合适的splitter参数。一般来说,如果数据集较小或者特征较少,可以使用'best';如果数据集较大或者特征较多,可以使用'random'。 默认为‘best’ 理解:就是说splitter设置为‘best’时是考虑所有的特征,在所有的特征中选择最好的一个作为划分结点的指标;而‘random’是先随机选择部分特征出来,再在这些筛选出来的指标中,找最好的一个作为划分结点的指标。这样操作可能会产生一些次优的分裂,但是却能够避免过拟合,提高模型的泛化能力(模型适用于新样本的能力)。 2.1.3剪枝参数

过拟合:学习器把训练样本学习的“太好”,将训练样本本身的特点当做所有样本的一般性质,导致模型的泛化能力下降。即训练集上表现的很好,但是在测试集上表现的很差。

# 模型对训练集的拟合程度 score_train = clf.score(Xtrain, Ytrain) score_train

sklearn提供了不同的策略:

max_depth

限制树的最大深度,超过设定深度的树枝全部剪掉

这是用得最广泛的剪枝参数,在高维度低样本量时非常有效。决策树多生长一层,对样本量的需求会增加一倍,所以限制树深度能够有效地限制过拟合。在集成算法中也非常实用。实际使用时,建议从=3开始尝试,看看拟合的效果再决定是否增加设定深度。

min_samples_leaf & min_samples_split

min_samples_leaf限定,一个节点在分枝后的每个子节点都必须包含至少min_samples_leaf个训练样本,否则分枝就不会发生,或者,分枝会朝着满足每个子节点都包含min_samples_leaf个样本的方向去发生。

min_samples_split限定,一个节点必须要包含至少min_samples_split个训练样本,这个节点才允许被分枝,否则分枝就不会发生。

那么究竟如何确定最优的剪枝参数呢?

绘制超参数学习曲线 test = [] for i in range(10): clf = tree.DecisionTreeClassifier(max_depth=i+1 ,criterion="entropy" ,random_state=30 ,splitter="best" ) clf = clf.fit(Xtrain, Ytrain) score = clf.score(Xtest, Ytest) test.append(score) plt.figure(dpi=200) plt.plot(range(1,11), test, color="red", label="max_depth") plt.legend() plt.show() image-20230317133114202 超参数的学习曲线,是一条以超参数的取值为横坐标,模型的度量指标为纵坐标的曲线,它是用来衡量不同超参数取值下模型的表现的线。在我们建好的决策树里,我们的模型度量指标就是score。 2.1.4目标权重参数 class_weight

对于样本不均衡问题,需要设置该参数。

在sklearn的决策树算法中,class_weight参数的取值可以是以下三种:

class_weight=None(默认值):表示不使用类别权重,所有类别的权重都为1。

class_weight='balanced':表示使用类别权重,但是权重大小是自动根据训练数据中的类别频率进行计算的。具体来说,权重大小为:

\[\frac{n_{samples}}{(n_{classes} * np.bincount(y))}$$, 其中n_{samples}表示样本总数,n_{classes}表示类别总数,np.bincount(y)表示每个类别的样本数。 \]

2.2重要属性和接口

属性是在模型训练之后,能够调用查看的模型的各种性质。对决策树来说,最重要的是feature_importances_,能够查看各个特征对模型的重要性。

sklearn中许多算法的接口都是相似的,比如说我们之前已经用到的fit和score,几乎对每个算法都可以使用。除了这两个接口之外,决策树最常用的接口还有apply和predict。

apply中输入测试集返回每个测试样本所在的叶子节点的索引,predict输入测试集返回每个测试样本的标签。

至此,我们已经学完了分类树DecisionTreeClassififier和用决策树绘图(export_graphviz)的所有基础。我们讲解了决策树的基本流程,分类树的八个参数,一个属性,四个接口,以及绘图所用的代码。

八个参数:criterion,两个随机性相关的参数(random_state,splitter),五个剪枝参数(max_depth,min_samples_split,min_samples_leaf,max_feature,min_impurity_decrease)

一个属性:feature_importances_

四个接口:fit,score,apply,predict

3.DecisionTreeRegressor 回归树

classsklearn.tree.DecisionTreeRegressor (criterion=’mse’, splitter=’best’, max_depth=None,

min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=None,

random_state=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, presort=False)

几乎所有参数,属性及接口都和分类树一模一样。需要注意的是,在回归树中,没有标签分布是否均衡的问题,因此没有class_weight这样的参数。

3.1重要参数、属性及接口 criterion

1)输入"mse"使用均方误差mean squared error(MSE),父节点和叶子节点之间的均方误差的差额将被用来作为

特征选择的标准,这种方法通过使用叶子节点的均值来最小化L2损失

2)输入“friedman_mse”使用费尔德曼均方误差,这种指标使用弗里德曼针对潜在分枝中的问题改进后的均方误差

3)输入"mae"使用绝对平均误差MAE(mean absolute error),这种指标使用叶节点的中值来最小化L1损失

属性中最重要的依然是feature_importances_,接口依然是apply, fifit, predict, score最核心。

\[MSE=\frac{1}{N}\sum_{i=1}^{N}{(f_i-y_i)^2} \]

然而,回归树的接口score返回的是R平方,并不是MSE.

from sklearn.datasets import load_boston from sklearn.model_selection import cross_val_score from sklearn.tree import DecisionTreeRegressor boston = load_boston() # 波士顿房价数据 regressor = DecisionTreeRegressor(random_state=0) #实例化 cross_val_score(regressor, boston.data, boston.target, cv=10, scoring = "neg_mean_squared_error") # 不设置scoring返回的是R方 # cross_val_score:交叉验证

交叉验证是用来观察模型的稳定性的一种方法,我们将数据划分为n份,依次使用其中一份作为测试集,其他n-1份作为训练集,多次计算模型的精确性来评估模型的平均准确程度。训练集和测试集的划分会干扰模型的结果,因此用交叉验证n次的结果求出的平均值,是对模型效果的一个更好的度量。

image-20230318093158941

n次测试也叫n折交叉验证

注意:所有接口中要求输入X_train和X_test的部分,输入的特征矩阵必须至少是一个二维矩阵。sklearn不接受任何一维矩阵作为特征矩阵被输入。

包括fit、apply、predict、score等

增维可以考虑reshape(-1,1)和使用np.newaxis



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有