table { font-size: 10pt;}
分类算法学习总结 - 决策树
因为最近在工作上的需要,对基于机器学习的分类算法比较感兴趣
对事物进行分类是比较常见的一种应用,包括对邮件,文本进行分类,对会员,行为,安全性等方面做处分类。 目前了解的情况:贝叶斯,决策树,神经网络, SVM 是比较流行的几种分类算法, 比如文本分类中经常用到 贝叶斯算法。
这篇文章主要介绍一下决策树
下面是一个很多书上经常给出的,根据各种天气情况,判断是否适合运动的决策树
相对于其他分类算法,决策树的优点是:
1 、决策过程易于理解
2 、可以转换成逻辑表达式的形式。
3 、可接受非数值型输入 ( 相对神经网络来说,不需要做预处理方面工作 )
决策树主要的适用场景是:
1 、各个决策的属性可以用 key=value 形式来表示
2 、结论并不特别多,可以用离散的值来表示
不太适用的场合:
大量数值型输入和输出的情况,树会比较庞大,准确性下降。
决策树的使用方法:
1 、根据训练数据,生成决策树
2 、使用生成好的决策树,接受新信息进行决策。
下面是《 Collective Intelligence 》上的一个例子,
网站提供了 None, Basic, Premium 三种会员级别,是根据一个网站根据访问用户的一些行为,预测哪些用户可能成为哪种类型的会员,下表列出了网站上的一些历史统计数据:
其中最后一列 Service chosen 是结果,表示会员选择了哪种服务。
一、决策树建立过程
建立决策树常见算法有 CART, C4.5 等
过程是一个自顶向下的递归过程,每一步都需要选择一个 合适的属性 - 值对 ,把整个集合拆分成左右两个子树。
假设我们随便选一个属性:所在地 =USA ,集合被拆成以下两个:
集合:所在地 =USA
集合:所在地 <>USA
这时我们会发现,按照会员所在地 =USA 来判断是不合适的,因为两个列表中,都包括了各种类型的会员。
我们换一个属性,用来源 =Google 来拆分,结果如下:
集合:来源 =google
集合:来源 <>google
这次的结果比通过地区 =USA 来拆分好多了,已经可以看出一些规律,历史的付费会员都是从 Google 引入的,假设网站要做一些推广的话,可能在 Google 上花点钱更值,呵呵。
那么问题就是,这么多的属性,怎么才能选出合适的呢?
从上面例子可以看出,有一种选择属性的标准,就是每次进行拆分后,被拆分出的两个集合应该倾向于更有序,即出现的可能结果 ( 上例:加入的服务 ) 越少越好。
在信息学上,可以用 熵 来表示一个集合的混乱程度,熵的定义如下:
其中, p(x) 是表示某一种可能的结果在集合中出现的概率 ,b 通常取 2 为底的对数,熵越高,集合越混乱,熵越低,集合越有序,当熵 =0 时,集合中只有一种结果,是最理想的状况。
例如 , 来源 =google 的集合中 ,Premium 出现概率是 3/5,Basic 和 None 出现概率都是 1/5
H ( X ) = -(0.6*log2(0.6) + 0.2*log2(0.2) + 0.2*log2(0.2)) = 1.37
同样计算得出其他集合的值:
按照所在地 =USA 拆分:
集合 ( 所在地 <>USA) 的熵是: 1.48
按照来源 =Google 拆分:
集合 ( 来源 =Google) 的熵是: 1.37
集合 ( 来源 <>Google) 的熵是: 1.0
从熵上可以看出,按照来源 =google 拆分出的两个集合熵更低,所以比按照所在地 =USA 拆分更理想。
所以,在递归创建每一层子树时,可以这样来做:
1 )计算当前集合 X 的熵
2 )尝试用每一个属性 = 值对,把当前集合拆分成 X1,X2 两个集合
3 )分别计算两个子集合的熵,并计算相对于当前集合 X , X1 , X2 熵的降低幅度。
4 )选出拆分后熵降低最多的属性 = 值对,以此来进行拆分。
其中 3 )中的拆分后熵降低程度,可以用信息增益来表示:
GAIN=H(X) – P(X1)H(X1) – P(X2)H(X2)
上面的例子中整个原始集合有 15 行数据,熵是 1.50, 按照来源 =google 拆分后:
X1 有 5 行数据,熵是 1.37
X2 有 10 行数据,熵是 1.0
GAIN = 1.50 – 5/15 * 1.37 – 10/15 * 1.0 = 0.5
同样,按照所在地 =USA 拆分,可以算出,信息增益基本接近 0 。所以按照来源 =google 拆分,对集合向有序的方向发展,贡献更大。
每一级都按照信息增益选择属性拆分,最终递归创建的决策树是:
二、使用创建好的决策树进行分类
使用创建好的决策树进行分类比较简单,只要从根节点开始,对这个决策树递归访问即可:
input 表示待分类的数据,例如
input = [ 来源 :google, 所在地 :USA...........]
node = tree 的根节点
classify(input,node){
if 已经是叶子节点:
返回 node.value
key = node 的 key
value = input[key]
if value == node.value:
return classify(input, 右子树 )
else
return classify(input, 左子树 )
}
三、决策树的剪枝
根据训练数据建立起来的决策树,可能存在一个问题,就是过于精确,那么在真实情况下,可能并不能完全达到理想的效果,下面这个例子,看得会比较明显:
这是一个关于调整薪资方案的一个例子,右侧的树看似包含了所有情况,但实际上过分依赖了测试数据,过于精确,实用性并不大。因为在这家公司现实中看的话,加薪比例 <=2.5 ,基本上就不能说是一个好方案了。
决策树修剪是一个比较复杂的问题,一般都采用先用训练数据建好树,再后修剪的方式。
例如,创建好树后,可以自底向上,判断每一组有相同父节点的叶子节点,如果合并之后,熵的增加小于某个阀值,就合并成一个节点。例如上面 b ,假设合并到根节点 (wage increase first year) 的时候,不能再合并了,就把原来整个子树中最可能出现的结果 ( 图中看是 bad) ,挂到合并好的节点下面。
不过,关于修剪方面,我还没能了解很深,还望有经验的朋友指点。