CART决策树算法浅谈(分类树部分)

来源:互联网 发布:微赞源码安装教程 编辑:程序博客网 时间:2024/05/20 22:37

在有上一篇博文做铺垫的情况下,分类树算法的介绍就显得相对简单。这篇博客首先介绍GINI系数以及它的直观意义,再给出基于GINI系数的CART分类树算法实现。这样,CART算法的两部分就介绍完毕。

1. GINI系数

考虑集合D,D={(x,y)|x=A1,A2,...AN}代表该集合有A1~AN这N个特征,每个特征取值又可以分为Ki类(i<=N)。如果这个集合包含了m类,设取到其中一类的概率为Pi,则有放回地取出两个样本,它们属于不同类别的概率为

P=1i=1mpi

该数值反映了集合的纯粹程度,可以想象,如果集合只含有一类,那么该值将变为0。所以,该值越小表示集合中属于同一类样本的个体越多,这个反应纯粹程度的量就是GINI系数。
对样本进行分类其实就是将属于同一类的样本集中,属于不同类的样本分开。我们最小化GINI系数就可以实现这一功能。
在上述推导的基础上,如果基于某一个特征按照 和 将集合分裂成两个子集合(a为特征Ai的某一取值),该如何计算这两个集合的“纯度”?这就引入了基于特征的GINI系数。
Gini(D,Ai)=p(Ai=a)Gini(DAi=i)+p(Aia)Gini(DAii)

这个量可用于评价使用Ai作为分类标准时,所得到分类结果的“纯度”。

2. 树的生成

分类树的基本生成过程与上篇博客提到的回归树生成十分相似。不同点在于选择分枝特征的准则,这里使用的是GINI系数。树的具体生成步骤如下:
Step1:根据特征Ai的某一取值a,将集合D分为 和 两部分,计算GINI系数。
Step2:对D的每一个特征和特征的每一个取值分别计算GINI系数,取GINI系数最小者作为分类准则,将集合D分裂成两个子集合。以后的切分过程不再使用该特征。
Step3:对每个子集合递归地调用步骤1~2,直到GINI系数为0或者特征使用完为止。

3. 基于Python的CART实现

树的生成过程与上篇博客大同小异,所以这里只介绍基尼系数选择特征的函数。

def calGINI(data, feature):    # data已经剪过了    targetFeature = data[:, feature]  # 获得目标特征    label = data[:, -1]  # 标签    sampleNum = len(targetFeature)  # 总样本数    kind = np.unique([targetFeature])  # 特征中含有的类别    labelKind = np.unique([label])    # 特征中的每一个分量都要计算    gini = []    for kindF in kind:        g = 0.0        subClass = data[np.nonzero(targetFeature == kindF)[0], :]  # 获取满足条件的子数据集        cmpClass = data[np.nonzero(targetFeature != kindF)[0], :]  # 获得差集        subClassP = len(subClass) / (1.0 * sampleNum)  # 该分量等于该值的比例        # 拆分后的数据集应当不为空        if len(subClass) and len(cmpClass):            g = subClassP * (                1.0 - sum(np.power(                    [len(np.nonzero(subClass[:, -1] == labK)[0]) / (1.0 * len(subClass[:, -1])) for labK in labelKind],                    2))) \                + (1.0 - subClassP) * (                1.0 - sum(np.power(                    [len(np.nonzero(cmpClass[:, -1] == labK)[0]) / (1.0 * len(cmpClass[:, -1])) for labK in labelKind],                    2)))        else:            g = np.inf        gini.append(g)    # 寻找最大特征作为分割点    featureLoc = int(np.where(gini == np.amin(gini))[0][0])  # 可能有同时为为最小的,只取一个    return feature, kind[featureLoc], gini[featureLoc]  # 返回最优分割对应的分量和gini系数

上面的代码用于计算某一特征的最优gini系数分割值。首先在该特征的所有取值中选择一个,计算按照该值分裂样本之后的GINI系数。遍历所有取值,找出GINI系数最小的那个特征取值,返回它。这样就可以获得一个特征的最优分裂值。通过与其他特征进行对比,就可找到最优的分裂值。
详细代码我转了一份到github,地址为:https://github.com/FlyingRoastDuck/CART_REG
参考文献
[1] 李航. 统计学习方法 [M]. 北京:清华大学出版社, 2012: 65-70.
[2] Peter H. 机器学习实战 [M]. 北京:人民邮电出版社,2013: 161-170.

阅读全文
0 0