当前位置: 代码迷 >> 综合 >> Decision Tree 决策树 - ID3, C45, C50, CART...
  详细解决方案

Decision Tree 决策树 - ID3, C45, C50, CART...

热度:19   发布时间:2024-01-13 01:31:11.0
1. 是什么

决策树是最简单的也是最具解释性和表达性的一种机器学习算法,既可以处理分类问题(ID3,C45,C50),也可以处理回归问题(CART)。

它是根据特征(feature)的值逐步把数据分类,直到所有的叶子节点属于同一个类型结束。注意决策树都是贪婪的。


2. 关键概念

1. 如何确定哪个特征被优先选择用来分类。

根据某一个特征划分数据集,其划分前后信息熵会有变化。优先选择的特征是让给让信息熵变化最大或者信息熵增益比最大的特征。

不过,从另外一方面来说,也要避免选择日期或者非常特殊的特征来做决策点,因为这些特征不具备任何的泛化能力。

2. 如何避免过拟合。

对于决策树来说,如果树的高度过高,或者某个叶子节点的数据特别少,或者叶子节点非常多(后两者有关联),就有可能是过拟合,在匹配被预测数据的时候就不会有很好的性能。避免决策树学习中的过度拟合问题,通常通过两种方法:
(1)及早停止树增长,比如发现树的高度过高,叶节点过多,或者节点内数据过少。这是sci-kit learn库目前的做法。
(2)通过后剪枝减少决策树的节点的个数。
尽管上面第一种方法可能看起来更直接,但是对过度拟合的树进行后修剪被证明在实践中更成功。这是因为在第一种方法中精确的估计何时停止树增长很困难。后剪枝的算法基本上就是合并同一个根节点下面所有的叶节点成为一个大的节点,而选择哪些节点做合并则需要根据节点内部数据个数。


3. 算法分支(详情参见http://scikit-learn.org/stable/modules/tree.html)
  • ID3

选取能够得到最大信息增益(information gain)的特征为数据划分归类,直到全部划分结束而不对树的规模进行任何控制。

等树生成之后,执行后剪枝。

信息增益的潜在问题是,比如有一个数据集含有一个特征是日期或者ID,则该特征会得到最大的信息增益,但是显然在验证数据中不会得到任何的结果。C45的信息增益比就是解决这个问题的。

  • C45
选取能够得到最大信息增益率(information gain ratio)的特征来划分数据,并且像ID3一样执行后剪枝。
是ID3的后续版本并扩展了IDC的功能,比如特征数值允许连续,在分类的时候进行离散化。
信息增益率:
“Gain ratio takes number and size of branches into account when choosing an attribute, and corrects the information gain by taking the intrinsic information of a split into account (i.e. how much info do we need to tell which branch an instance belongs to).”
  • C50
这是最新的一个版本,是有许可的(proprietary license)。比之C45,减少了内存,使用更少的规则集,并且准确率更高。
  • CART
CART(Classification and Regression Trees)分类回归树,它使用基尼不纯度(Gini Impurity)来决定划分。Gini Impurity和information gain ratio的理解和区分在这里:
http://stats.stackexchange.com/questions/94886/what-is-the-relationship-between-the-gini-score-and-the-log-likelihood-ratio。
它和C45基本上是类似的算法,主要区别:1)它的叶节点不是具体的分类,而是是一个函数f(),该函数定义了在该条件下的回归函数。2)CART是二叉树,而不是多叉树。

4. 怎么用

sci-kit learn提供决策树,是基于优化的CART算法,使用方便简单,但是有两个问题:1)不如C50优化;2)sci-kit learn库并没有实现后剪枝(截至最新版0.16.0),所以防止过拟合的办法都是提前停止生长的方法,可以通过设置参数的方式控制。详情参加:http://scikit-learn.org/stable/modules/tree.html


使用:

from sklearn import tree
clf = tree.DecisionTreeClassifier() or clf = tree.DecisionTreeRegressor
clf = clf.fit(X, Y)
clf.predict([[..]])
clf.predict_proba([[..]])
(其中clf就是最终的分类器,而X是输入数据,Y是label。)


类和函数的原型:

class sklearn.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, class_weight=None)

输入参数展开说:

criterion: 划分的规则,默认是gini。“gini” = Gini Impurity,取值在0-1之间。“entropy” = 信息增益(information gain)。基尼系数通常是确定平衡的一个指数,用于评价一个国家的收入是否分配不均衡。这里的基尼不纯度基本上恰好相反:值最小,=0,表明分类之后的元素都归于某一类,越纯(实际上对应的基尼系数应该是越不平衡);越趋近于1,表明元素均匀的分散到各个分类里面。
splitter:划分节点的策略,默认是best,算法会根据criterion来选择最好的feature做分割。可以设置random,算法会随机选择feature做分割;但是实际上,也并非完全的随机,算法也会做一些避免造成泛化能力丢失的处理。
max_features: 划分的时候需要考虑多少特征,或者全部(默认值)或者一个子集。
max_depth: 最大树深度。避免过拟合的。
min_samples_split: 内部节点上,每一个节点至少需要有的sample个数。避免过拟合的。
min_samples_leaf:  叶子节点上,每一个节点至少需要有的sample个数。避免过拟合的。
min_weight_fraction_leaf: 没研究。
max_leaf_nodes: 最大叶子节点个数。他和max_depth互斥。避免过拟合的。
class_weight:分类的权重。没研究。
random_state : 随机种子,为splitter服务的。如果splitter=random,那么在对同一组数据做两次预测的时候,会有可能造成决策树不一样(很可能),其原因是使用了不同的随机种子(random_state),所以如果一直记录下来随机种子值并一直使用该值的话,就不会出现多次预测结果不一样的问题。

结果展开说:

tree_ : Tree 对象(sklearn.tree._tree.Tree),二叉树。根据这个tree_对象,可以还原整个决策树的决策过程。关于tree_的细节,可以参考sklearn的官网,如何把tree可视化,可以参照stackoverflow的问答(参考链接在后面):

    from sklearn import tree

    from StringIO import StringIO

    import pydot (需要首先安装pydot库)

    dot_data =StringIO()

    tree.export_graphviz(clf,out_file=dot_data)

    graph =pydot.graph_from_dot_data(dot_data.getvalue())

   graph.write_pdf("./iris.pdf")


classes_ : 分类的label。
n_classes_ : 分类个数。
feature_importances_ : 特征重要度。越大越重要,表明越是被优先选出来的。

max_features_ : 参与决策树的特征数。

5. 应用场景和限制

是监督的分类和回归算法。对噪声点的容忍性非常好。性能比较好。贪婪。

详情参阅:http://scikit-learn.org/stable/modules/tree.html


6. 参考

http://scikit-learn.org/stable/modules/tree.html

http://blog.csdn.net/google19890102/article/details/28611225

http://underthehood.blog.51cto.com/2531780/610442

http://blog.csdn.net/cyningsun/article/details/8735169

http://stackoverflow.com/questions/25274673/is-it-possible-to-print-the-decision-tree-in-scikit-learn

  相关解决方案