CART回归树对于特征的处理

关注WX公众号: commindtech77, 获得数据资产,推荐系统源码等相关白皮书下载地址

回复关键字:推荐系统
下载《新闻资讯个性化推荐系统源码及白皮书》

CART算法的重要基础包含以下三个方面:

(1)二分(Binary Split):在每次判断过程中,都是对观察变量进行二分。

CART算法采用一种二分递归分割的技术,算法总是将当前样本集分割为两个子样本集,使得生成的决策树的每个非叶结点都只有两个分枝。因此CART算法生成的决策树是结构简洁的二叉树。因此CART算法适用于样本特征的取值为是或非的场景,对于连续特征的处理则与C4.5算法相似。

(2)单变量分割(Split Based on One Variable):每次最优划分都是针对单个变量。

(3)剪枝策略:CART算法的关键点,也是整个Tree-Based算法的关键步骤。

剪枝过程特别重要,所以在最优决策树生成过程中占有重要地位。有研究表明,剪枝过程的重要性要比树生成过程更为重要,对于不同的划分标准生成的最大树(Maximum Tree),在剪枝之后都能够保留最重要的属性划分,差别不大。反而是剪枝方法对于最优树的生成更为关键。

CART对离散分布、且取值数目>=3的特征的处理:

因为CART树是二叉树,所以对于样本的有N>=3个取值的离散特征的处理时也只能有两个分支,这就要通过组合人为的创建二取值序列并取GiniGain最小者作为树分叉决策点。如某特征值具有[‘young’,’middle’,’old’]三个取值,那么二分序列会有如下3种可能性(空集和满集在CART分类中没有意义):

[((‘young’,), (‘middle’, ‘old’)), ((‘middle’,), (‘young’, ‘old’)), ((‘old’,), (‘young’, ‘middle’))]

采用CART算法,就需要分别计算按照上述List中的二分序列做分叉时的Gini指数,然后选取产生最小的GINIGain的二分序列做该特征的分叉二值序列参与树构建的递归。如果某特征取值有4个,那么二分序列组合就有7种,5个取值就有15种组合,创建多值离散特征二分序列组合可采用Python的itertools包,程序如下:

  1. from itertools import *
  2. import pdb
  3. def featuresplit(features):
  4.     count = len(features)
  5.     featureind = range(count)
  6.     featureind.pop(0) #get value 1~(count-1)
  7.     combiList = []
  8.     for i in featureind:
  9.         com = list(combinations(features, len(features[0:i])))
  10.         combiList.extend(com)
  11.     combiLen = len(combiList)
  12.     featuresplitGroup = zip(combiList[0:combiLen/2], combiList[combiLen-1:combiLen/2-1:-1])
  13.     return featuresplitGroup
  14. if __name__ == ‘__main__‘:
  15.     test= range(3)
  16.     splitGroup = featuresplit(test)
  17.     print ‘splitGroup’, len(splitGroup), splitGroup
  18.     test= range(4)
  19.     splitGroup = featuresplit(test)
  20.     print ‘splitGroup’, len(splitGroup),splitGroup
  21.     test= range(5)
  22.     splitGroup = featuresplit(test)
  23.     print ‘splitGroup’, len(splitGroup),splitGroup
  24.     test= [‘young’,’middle’,’old’]
  25.     splitGroup = featuresplit(test)
  26.     print ‘splitGroup’, len(splitGroup),splitGroup

因此CART不适用于离散特征有多个取值可能的场景。此时,若定要使用CART,则最好预先人为的将离散特征的取值缩减。

那么对于二分后的左右分支,如果特征取值tuple中元素多于2个,该特征是否还要继续参与当前子数据集的二分呢?TBD

我认为需要,因此该特征继续参与分类决策树递归,直至左右分支上该特征的取值都是唯一的(即不再包含该特征)。那么离散特征的datasplit函数就应该:如果按照当前分支特征分叉后,分支上特征取值tuple>=2,则分支子数据集保留该特征,该tuple继续参与上的树构建的递归;否则分支子数据集删除该特征。

  1. def splitDataSet(dataSet, axis, valueTuple):
  2.     ”’return dataset satisfy condition dataSet[i][axis] == valueTuple,
  3.     and remove dataSet[i][axis] if len(valueTuple)==1”’
  4.     retDataSet = []
  5.     length = len(valueTuple)
  6.     if length ==1:
  7.       for featVec in dataSet:
  8.         if featVec[axis] == valueTuple[0]:
  9.             reducedFeatVec = featVec[:axis]     #chop out axis used for splitting
  10.             reducedFeatVec.extend(featVec[axis+1:])
  11.             retDataSet.append(reducedFeatVec)
  12.     else:
  13.       for featVec in dataSet:
  14.         if featVec[axis] in valueTuple:
  15.             retDataSet.append(featVec)
  16.     return retDataSet

CART对连续特征的处理:

连续属性参考C4.5的离散化过程,区别在于CART算法中要以GiniGain最小作为分界点选取标准。是否需要修正?处理过程为:

先把连续属性转换为离散属性再进行处理。虽然本质上属性的取值是连续的,但对于有限的采样数据它是离散的,如果有N条样本,那么我们有N-1种离散化的方法:<=vj的分到左子树,>vj的分到右子树。计算这N-1种情况下最大的信息增益率。另外,对于连续属性先进行排序(升序),只有在决策属性(即分类发生了变化)发生改变的地方才需要切开,这可以显著减少运算量。

(1) 对特征的取值进行升序排序

(2) 两个特征取值之间的中点作为可能的分裂点,将数据集分成两部分,计算每个可能的分裂点的GiniGain。优化算法就是只计算分类属性发生改变的那些特征取值

(3)选择GiniGain最小的分裂点作为该特征的最佳分裂点(注意,若修正则此处需对最佳分裂点的Gini Gain减去log2(N-1)/|D|(N是连续特征的取值个数,D是训练数据数目)

实现连续特征数据集划分的Python程序为(采用Numpy matrix,连续特征取值就可以省略排序这一步了):

  1. def binSplitDataSet(dataSet, feature, value):
  2.     mat0 = dataSet[nonzero(dataSet[:,feature] > value)[0],:][0]
  3.     mat1 = dataSet[nonzero(dataSet[:,feature] <= value)[0],:][0]
  4.     return mat0,mat1

其中dataset为numpy matrix, feature为dataset连续特征在dataset所有特征中的index,value即为feature的一个取值。

必须注意的是:根据离散特征分支划分数据集时,子数据集中不再包含该特征(因为每个分支下的子数据集该特征的取值就会是一样的,信息增益或者Gini Gain将不再变化);而根据连续特征分支时,各分支下的子数据集必须依旧包含该特征(当然,左右分支各包含的分别是取值小于、大于等于分裂值的子数据集),因为该连续特征再接下来的树分支过程中可能依旧起着决定性作用。

训练数据汇总离散特征和连续特征混合存在时的处理:

C4.5和CART算法决策树创建过程中,由于离散特征和连续特征的处理函数不同。当训练数据中两种特征并存时必须能够识别分布类型,从而调用相应的函数。那么有两种方法:

(1)每个特征注明是连续分布还是离散分布,如0表示离散、1表示连续.如此训练、决策时都可以分辨分布类型。

(2)函数中根据特征取值的个数判定,如featureValueCount>10(当然,离散特征取值不可能这么多)则为连续分布,否则为离散分布。此时构建的决策树模型中,必须注明特征的分布类型(如构建一个List,长度为featureCount,其中元素0:离散,1:连续)。

Note:对于取值为是或者否的离散特征,将其按离散或者连续分布处理均可。按照连续分布反而简单,取std=0.5即可简单的实现split。此时分布判断标准更改为featureValueCount>20 or ==2。

(3) 利用独热编码(OneHotEncoding),Python sklearn 的preprocessing提供了OneHotEncoder()能够将离散值转换成连续值处理。独热编码即 One-Hot 编码,又称一位有效编码,其方法是使用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候,其中只有一位有效。对于每一个特征,如果它有m个可能值,那么经过独热编码后,就变成了m个二元特征。并且,这些特征互斥,每次只有一个激活。因此,数据会变成稀疏的。这样做的好处主要有:解决了分类器不好处理属性数据的问题、在一定程度上也起到了扩充特征的作用。

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值