分类树
-
sklearn.tree.DecisionTreeClassifier
pythonsklearn.tree.DecisionTreeClassifier (criterion='gini' # 不纯度计算方法 , splitter='best' # best & random , 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 )
重要参数
criterion
-
criterion
这个参数正是用来决定不纯度的计算方法的。sklearn
提供了两种选择:- 输入"entropy",使用信息熵(
Entropy
),sklearn
实际计算的是基于信息熵的信息增益(Information Gain),即父节点的信息熵和子节点的信息熵之差。 - 输入"gini",使用基尼系数(Gini Impurity)
E n t r o p y ( t ) = − ∑ i = 0 c − 1 p ( i ∣ t ) log 2 p ( i ∣ t ) Entropy(t) = - \sum \limits_{i=0}^{c-1} p(i|t)\log{_2}p(i|t) Entropy(t)=−i=0∑c−1p(i∣t)log2p(i∣t)
G i n i ( t ) = 1 − ∑ i = 0 c − 1 p ( i ∣ t ) 2 Gini(t) = 1 - \sum_{i=0}^{c-1}p(i|t)^2 Gini(t)=1−i=0∑c−1p(i∣t)2
其中t代表给定的节点,i代表标签的任意分类, p ( i ∣ t ) p(i|t) p(i∣t) 代表标签分类i在节点t上所占的比例。注意,当使用信息熵 时,
sklearn
实际计算的是基于信息熵的信息增益(Information Gain),即父节点的信息熵和子节点的信息熵之差。 比起基尼系数,信息熵对不纯度更加敏感,对不纯度的惩罚最强。但是在实际使用中,信息熵和基尼系数的效果基 本相同。信息熵的计算比基尼系数缓慢一些,因为基尼系数的计算不涉及对数。另外,因为信息熵对不纯度更加敏 感,所以信息熵作为指标时,决策树的生长会更加"精细",因此对于高维数据或者噪音很多的数据,信息熵很容易 过拟合,基尼系数在这种情况下效果往往比较好。当模型拟合程度不足的时候,即当模型在训练集和测试集上都表 现不太好的时候,使用信息熵。当然,这些不是绝对的。参数 criterion 如何影响模型? 确定不纯度的计算方法,帮忙找出最佳节点和最佳分枝,不纯度越低,决策树对训练集 的拟合越好 可能的输入有哪 些? 不填默认基尼系数,填写gini使用基尼系数,填写entropy使用信息增益 怎样选取参数? 通常就使用基尼系数 数据维度很大,噪音很大时使用基尼系数 维度低,数据比较清晰的时候,信息熵和基尼系数没区别 当决策树的拟合程度不够的时候,使用信息熵,两个都试试不好就换另一个 python# -*- coding: utf-8 -*- """ ************************************************** @author: Ying @software: PyCharm @file: 分类树_criterion.py @time: 2021-08-20 16:13 ************************************************** """ from sklearn import tree from sklearn.datasets import load_wine from sklearn.model_selection import train_test_split import pandas as pd import graphviz # 加载数据 wine = load_wine() data = pd.DataFrame(wine.data, columns=wine.feature_names) # X target = pd.DataFrame(wine.target) # y # 划分训练测试集 X_train, X_test, y_train, y_test = train_test_split(data, target, test_size=0.3) # 两种criterion for criterion_ in ['entropy', 'gini']: clf = tree.DecisionTreeClassifier(criterion=criterion_) clf.fit(X_train, y_train) score = clf.score(X_test, y_test) # 返回预测的准确度 print(f'criterion:{criterion_} \t accurancy : {score}') # 保存决策树图 feature_name = ['酒精', '苹果酸', '灰', '灰的碱性', '镁', '总酚', '类黄酮', '非黄烷类酚类', '花青素', '颜色强度', '色调', 'od280/od315稀释葡萄酒', '脯氨酸'] dot_data = tree.export_graphviz(clf , feature_names=feature_name , class_names=["琴酒", "雪莉", "贝尔摩德"] , filled=True # 填充颜色 , rounded=True # 圆角 ) graph = graphviz.Source(dot_data) graph.render(view=True, format="pdf", filename=f"decisiontree_pdf_{criterion_}") # 特征重要性 feature_importances = clf.feature_importances_ for i in [*zip(feature_name, feature_importances)]: print(i) print()
python"""输出如下""" criterion:entropy accurancy : 0.8703703703703703 ('酒精', 0.0) ('苹果酸', 0.0) ('灰', 0.0) ('灰的碱性', 0.02494246008989065) ('镁', 0.0) ('总酚', 0.0) ('类黄酮', 0.3296114164674079) ('非黄烷类酚类', 0.0) ('花青素', 0.0) ('颜色强度', 0.14329965511242485) ('色调', 0.0) ('od280/od315稀释葡萄酒', 0.0) ('脯氨酸', 0.5021464683302767) criterion:gini accurancy : 0.8148148148148148 ('酒精', 0.0) ('苹果酸', 0.0) ('灰', 0.0) ('灰的碱性', 0.0) ('镁', 0.04779989924874613) ('总酚', 0.06725255711062922) ('类黄酮', 0.3230308396876504) ('非黄烷类酚类', 0.0) ('花青素', 0.0235378291755189) ('颜色强度', 0.0) ('色调', 0.0) ('od280/od315稀释葡萄酒', 0.0878400745934749) ('脯氨酸', 0.45053880018398057)
- 输入"entropy",使用信息熵(
-
回到模型步骤,每次运行score会在某个值附近 波动,引起每次画出来的每一棵树都不一样。它为什么会不稳定呢?如果使用其他数据集,它还会不稳定吗?
无论决策树模型如何进化,在分枝上的本质都还是追求某个不纯度相关的指标的优化,而正如我 们提到的,不纯度是基于节点来计算的,也就是说,决策树在建树时,是靠优化节点来追求一棵优化的树,但最优 的节点能够保证最优的树吗?集成算法被用来解决这个问题:sklearn表示,既然一棵树不能保证最优,那就建更 多的不同的树,然后从中取最好的。怎样从一组数据集中建不同的树?在每次分枝时,不从使用全部特征,而是随 机选取一部分特征,从中选取不纯度相关指标最优的作为分枝用的节点。这样,每次生成的树也就不同了。
random_state&spliter
-
random_state
用来设置分枝中的随机模式的参数,默认None
,在高维度时随机性会表现更明显,低维度的数据 (比如鸢尾花数据集),随机性几乎不会显现。输入任意整数,会一直长出同一棵树,让模型稳定下来。 -
splitter
也是用来控制决策树中的随机选项的,有两种输入值:- best
- random
输入"best",决策树在分枝时虽然随机,但是还是会 优先选择更重要的特征进行分枝(重要性可以通过属性
feature_importances_
查看)输入"random",决策树在 分枝时会更加随机,树会因为含有更多的不必要信息而更深更大,并因这些不必要信息而降低对训练集的拟合。这 也是防止过拟合的一种方式。当你预测到你的模型会过拟合,用这两个参数来帮助你降低树建成之后过拟合的可能 性。当然,树一旦建成,我们依然是使用剪枝参数来防止过拟合。
python# -*- coding: utf-8 -*- """ ************************************************** @author: Ying @software: PyCharm @file: 2、分类树_random_state&spliter.py @time: 2021-08-20 16:58 ************************************************** """ from sklearn import tree from sklearn.datasets import load_wine from sklearn.model_selection import train_test_split import pandas as pd import graphviz # 加载数据 wine = load_wine() data = pd.DataFrame(wine.data, columns=wine.feature_names) # X target = pd.DataFrame(wine.target) # y # 划分训练测试集 X_train, X_test, y_train, y_test = train_test_split(data, target, test_size=0.3) clf = tree.DecisionTreeClassifier(criterion='gini' , random_state=30 , splitter='best') clf.fit(X_train, y_train) score = clf.score(X_test, y_test) # 返回预测的准确度 # 保存决策树图 feature_name = ['酒精', '苹果酸', '灰', '灰的碱性', '镁', '总酚', '类黄酮', '非黄烷类酚类', '花青素', '颜色强度', '色调', 'od280/od315稀释葡萄酒', '脯氨酸'] dot_data = tree.export_graphviz(clf , feature_names=feature_name , class_names=["琴酒", "雪莉", "贝尔摩德"] , filled=True # 填充颜色 , rounded=True # 圆角 ) graph = graphviz.Source(dot_data) graph.render(view=True, format="pdf", filename="decisiontree_pdf") # 特征重要性 feature_importances = clf.feature_importances_ a = pd.DataFrame([*zip(feature_name, feature_importances)]) a.columns = ['feature', 'importance'] a.sort_values('importance', ascending=False, inplace=True) print(a)