决策树分类(DMTree)算法研究报告

算法原理

背景知识

决策树(Decision Tree)是一个类似流程图的树结构,其中每个内部节点表示在一个属性上的测试,每个分支代表一个测试输出,而每个树叶节点代表类或类分布。

下图是一个简单的决策树:
他代表了概念buys_computer,指出某数据集上的顾客是否可能购买计算机。其中每个内部(非树叶)节点表示一个属性上的测试,每个树叶节点代表一个类(buys_computer=yes或者buys_computer=no)。

决策树归纳的基本算法是贪心算法,他以自顶向下递归的各个击破方式构造决策树。DMTree算法是根据决策树算法的原理得出的,同时参考了SLIQ算法、RainForest决策树框架的思想。

算法基于在不同属性的不同值上获得最大的信息获取率(可以是gini指标、information gain指标等等)对训练样本集不断地进行分裂,经过分裂之后得到的每一个子训练集会再次分裂,这个过程以广度优先的方式展开,重复进行,直到所有节点都满足停止继续分裂的条件。

在模型生长的过程中和过程结束之后,需要使用MDL算法对生成的模型结果进行裁剪,以避免训练数据中的噪声和孤立点样本影响模型最终的准确率,进而造成过度适应(over fit)。

在生成的模型结果方面,该算法与普通决策树不同的是,DMTree算法生成的结果是一个二叉树。每个内部节点只有两种分类原则:对于数值型字段,它代表左子树x<=A,右子树x>A,其中A是一个数值;对于种类型字段,它代表左子树xÎB,右子树xÏB,其中B是字段所有可能值的一个子集。生成的二叉树具有比普通的决策树模型更优秀的模型表述能力,同时通过自上而下的遍历,模型结果也很容易转换成容易理解的规则集。

算法原理

已知:

a)         每个数据样本用一个n维特征向量表示,分别描述n个属性样本的n个度量。

b)         有m个类

c)         每个训练样本有一个类型属性Cs个样本构成了训练数据集S

求解:

给出一个决策树分类模型,预测一个新的数据样本X所属的类。

算法的思路:

1. 算法概述

首先,扫描数据库中的数据集,将DBMS表中的数据转移到Disk上。以后一直对磁盘数据进行操作,这样比对直接DBMS进行读取速度要快很多,同时不需要将数据全部保存在内存中。

数据准备完成以后,输入数据集和被划分成训练数据集和测试数据集。挖掘算法将在此基础上运行。

算法主体使用了一个决策树,对于叶子节点维护了一个队列。算法使用广度优先策略一层一层的构造生长整个决策树的结构,每次都在新生长出来的那一层的每个叶子节点里面寻找最佳分割点,进而进行划分。

算法主体的结构如下:

 

Do A Sampling                      //按照参数指定比例进行抽样

while(当前叶子节点队列不为空) do      //对训练集进行树生成的训练

For Each 叶子节点 do

Generate the AVC-Group From the DataPartition

For each  字段 do            //最佳分割的计算

Call CL.find_best_partitioning(AVC-set of p);

End;

CL.decide-splitting_criterion();

Create LeftChild and RightChild;

End;

PruneWholeTree;

For Each 老的 叶子节点 do

If(的确需要分割)

Use best split to partition  D into D1, D2;

Put LeftChild and RightChild Into New  叶子节点队列;

End;

End;

PruneWholeTree();

在测试集上进行打分,得出树的准确率;

 

其中,数据结构AVC_Group是对于输入的训练数据的压缩,它利用hash表分别压缩存放数值型和种类型字段。由于采用了先进的索引技术,AVC_Group的使用可以大大降低算法的内存消耗量,提高算法的运行效率。AVC_Group的计算需要利用在DBMS转存到File时候形成的一些统计信息,如Max, Min, 种类字段的不同值的个数等等。

 

总的来说,这种算法的好处:

1)  可以采用多种 分割指数:Gini,Entropy,Twoing Power-Modified Twoing,等等。

2)  潜在很大的并行化处理的可能。

3)  将修剪和生成结合起来,避免了树得太深扩张。同时使用MDL方法,免除了测试集的多次使用。

4)    消除了对于内存的巨大要求。只要能够将AVC-Group放入内容就可以了。

2. 修剪问题

在算法的运行过程中需要随时对决策树结构进行修剪,以避免“过度适应”,修建的原则称为MDL原则,使用MDL方法对决策树进行剪枝的目的就是寻找一棵能用最少的bit来对其进行描述的树。

对一棵决策树进行描述包括以下三方面的内容:

1)      对树的结构进行描述

2)      对每个内部节点中的分割进行描述,包括所选的属性和分割的值。

3)      对每个叶子节点中属于各个类的数据进行描述。

三方面的内容如下:

1. 对树的结构进行描述。只需要一个bit就可以区别是内部节点(1)还是叶子节点(0)。由于是二叉树,所以这些信息就可以足以表示树的结构了。

2.对分割的描述。首先是对属性的选择,假设一共有a个属性,那么需要log a个bit。然后是对分割值的描述。假设所选属性中有v个不同的值,那么对于数值字段需要log v-1个bit;对于种类字段,需要log 2v-2个bit。将两个相加就是对分割的描述(记为Csplit(N))。

3.对每个叶子节点中数据的描述。假设所有数据中一共有k个类别。该结点中包含n条记录,每个类别包含ni条记录。则描述数据需要的bit计算如下:

 

注:最后一个符号为Gamma。定义如下:Gamma(x+1)=x*Gamma(x) (x>0),Gamma(1/2)=sqrt(PI),Gamma(1)=1;

从而Gamma(k/2)=(m-1)!  如果k=2m;Gamma(k/2)=(m-1)! * (1/2) * sqrt(PI)  k=2m+1。

 

float  ComputerCost&Prune(Node N)

{

if ( N is a leaf)   return   (C(S)+1)

//N1 and N2 are N’s Children

fMinCost1 =ComputerCost&Prune(N1);

fMinCost2=ComputerCost&Prune(N2);

fMinCostN =min(C(S)+1,Csplit(N)+1+fMinCost1+fMinCost2);

if(fMinCostN =C(S)+1)

Prune child nodes N1 and N2 from tree

Return fMinCostN

}

 

用于运行中修剪的算法

 

float  ComputerCost&PruneDuringBuilding(Node N)

{

if N is a “yet to be expanded” leaf

return  lower bound on subtree cost at N

if N is a  “pruned” or “not expandable leaf return (C(S)+1)

//N1 and N2 are N’s Children

fMinCost1 =ComputerCost&PruneDuringBuilding (N1);

fMinCost2=ComputerCost&PruneDuringBuilding (N2);

fMinCostN =min(C(S)+1,Csplit(N)+1+fMinCost1+fMinCost2);

if(fMinCostN =C(S)+1)

{

Prune child nodes N1 and N2 from tree

Delete nodes N1 and N2 and all their children from tree

Mark node N as pruned

}

Return fMinCostN

}

lower bound on subtree cost at N 的计算可以分成不同的精细程度。

1) 就作为1计算

2) 更加精确的计算方法

当前版本采用SLIQ,SPRINT算法中使用的C(S)的计算方法,C(S) =等于节点中不属于大多数类别的记录一个之和。这里需要考虑 CostMatrix和Priors

3. CL的采用

当前采用类似 SLIQ的方法,分割指标使用Gini。今后的版本中,会不断的扩充可以采用的分割指标。

 

For each 字段

{

If  字段是 数值字段

{

遍历所有可能的分割,计算每种分割的 Gini

然后取得一个最佳的分割

}

if 字段是种类字段

{

if (种类的值 <K)

{

完全遍历所有的组合,计算每种的Gini

取得一个最佳的分割

}

if(种类的值 >=K)

{

采用贪心算法进行搜索,计算每次的Gini

取得一个最佳的分割

}

}

对于不同字段的分割中,选择出一个最佳的分割,作为该节点的分割。

}

 

4. 分割指标与最佳分割的计算

分割指标与最佳分割的计算参考下面的算法,

 

Int BestSplit_Gini()

begin

for( each 属性) do

if(数值字段或者日期字段) then

BestSplit_Gini_Numerical()

if(种类字段) then

BestSplit_Gini_Categorical()

计算是不是比当前最佳分割要好:这里需要将 ColumnAdjust
结合进来,其最后的GiniGain应该是
=原始的GiniGain / ColumnAdjust。

更新信息:最佳分割所在字段,最佳分割的值

end;

end;

 

 

BestSplit_Gini_Numerical()

begin

数值从小到大一个个进行计算

初始时,所有的记录都在右子树上,每次将这个数值的记录移动到左子树上

Calculate_Gini(本节点记录分布,

左子节点记录分布,右子节点记录分布)

如果Gini值更好,更新最好分割的数值和Gini值

end;

 

 

BestSplit_Gini_Categorical()

begin

使用贪心算法进行求解

end;

 

 

Calcaulate_Gini(本节点记录分布,左子节点记录分布,右子节点记录分布)

begin

//计算这种分割的Gini Gain

这种分割的Gini Gain =Gini_本节点

—(P1 * Gini左子节点 + P2 * Gini右节点)

p1,p2表示左右节点中记录的比率。

一个节点的Gini值= 。其中是某个类别出现的次数

这里需要将 Class的Prior结合进来,

设类别I的Prior为Ri,那么计算公式变成

Gini值=

end;

限制条件

输入数据,至少有一个字段是种类字段,用于输出类别标签。

输出结果

算法的最终输出结果为一棵可以导出分类准则的决策树,基于这棵树,用测试集进行打分,可以得到这个模型的准确率。

同时,基于这个结构,对于某个未知类别样本X,可以输出它的类别,形式为一个简短的report。

算法优点和缺点

优点:

a)         计算具体类别的工作放在运行期,用户使用该模型会相当的快。

b)         模型准确率比较高。

c)         直观的规则或者谓词表达模型结果。

缺点:

a)         建模速度比较慢。

可能的改进:

丢失值的处理。


算法举例

给定如下的表格作为算法的训练数据集:

 

需要给出类别字段:buys_computer

 

算法首先把训练集导入到磁盘文件中。然后,根据文件生成AVC_Group,一个AVCGroup包含若干个AVCSet,每个字段对应一个AVCSet,对于数值型和种类型字段,将生成不同类型的AVCSet:数值型字段的AVCSet是一个长度为BinCount(默认值1000)的hash表,表中存放着不同的值以及不同值的个数。当hash函数发生冲突的时候,解决冲突的方案是采用链表的方式。种类型字段不同的种类值存放在不同的AVCItem里面,没有使用hash。

当AVC_Group制作完成以后,再加上一些对输入数据集的校验工作,数据准备基本完成了,开始进入创建决策树结构的算法运行阶段。

初始的时候,只有一个节点:根结点。以后每次树生长一层,操作只针对当前所有的叶子节点。

对每一个节点而言,算法使用gini指标计算该在不同的属性上不同的划分准则下得到的节点的gini指数,对数值字段使用遍历的方法,对种类字段使用贪心算法,目的是为了寻找gini指标最高的(对数值字段而言是较高的)划分。

找到划分以后,执行节点分裂,同时进行运行期的修剪。

当所有的节点都达到了生长极限(满足预定的停止分裂标准),整个算法就宣告停止。在此之后,还将进行一次整体修剪,以优化结构。

 

当所有的任务完成之后,需要进行模型结果的打分,打分的结果(模型准确率)将作为结果返还给用户。

Apriori算法研究报告

算法原理

背景知识

Apriori算法是Agrawal等于1994年提出的一个挖掘顾客交易数据库中项集间的关联规则的重要方法,是迄今最有影响挖掘布尔关联规则频繁项集的关联规则算法。该关联规则在分类上属于单维、单层、布尔关联规则。

算法原理

Apriori算法主要分成两步:首先找出数据中所有的频繁项集,这些项集出现的频繁性要大于或等于最小支持度。然后由频繁项集产生强关联规则,这些规则必须满足最小支持度和最小置信度。算法的总体性能由第一步决定,第二步相对容易实现。

第一步主要是基于Apriori性质:频繁项集的所有非空子集都必须也是频繁的。因此这一步主要由连接和剪枝两个过程组成。连接:频繁项集Lk-1与自己连接产生候选k-项集的集合Ck。假定事务和项集都按字典次序排序。连接Lk-1Lk-1,Lk-1中的l1和l2项是可连接的,如果(l1[1]=l2[1] )∧(l1[2]=l2[2] )∧…∧(l1[k-2]=l2[k-2] )∧(l1[k-1]<l2[k-1] ),连接的结果项集为l1[1] l1[2]…l1[k-1]l2[k-1]。剪枝:若一个候选k-项集的(k-1)-子集不在Lk-1中,则该候选集不可能是频繁的,可由Ck中删除。

Ck可存在hash-tree中。

发现频繁项集的Apriori算法的伪码如下:

输入:事务数据库D;最小支持度阈值min_sup。

输出:D中的频繁项集L。

(1)                  L1 = find_frequent_1-itemsets(D);   //找出频繁1-项集

(2)                  for (k = 2;  Lk-1 ¹ F;  k++)

(3)                  {

(4)                      Ck= apriori_gen(Lk-1, min_sup);   //产生新的候选集

(5)                      for all transactions tÎD

(6)                      {

(7)                           Ct=subset(Ck, t);    //事务t中包含的候选集

(8)                           for all candidates cÎ Ct

(9)                              c.count++;

(10)                   }

(11)                   Lk = {c Î Ck | c.count³min_sup}

(12)               }

(13)                return  L = ∪k Lk;

 

procedure apriori_gen(Lk-1,min_sup)

(1)            for all l1∈Lk-1

(2)            {

(3)              for all l2∈Lk-1

(4)              {

(5)                  if (l1[1]=l2[1] )∧(l1[2]=l2[2] )∧…∧(l1[k-2]=l2[k-2] )∧(l1[k-1]<l2[k-1])

(6)                  then

(7)                  {

(8)                       c = l1 ∞ l2;                      //连接

(9)                       if has_infrequent_subset(c, Lk-1) then

(10)                        delete c;           //剪枝

(11)                    else add c to Ck;

(12)                }

(13)            }

(14)         }

(15)         return  Ck;

 

procedure has_infrequent_subset(c,Lk-1)

(1)            for all (k -1)-subset s of c

(2)            {

(3)                if sLk-1 then

(4)                   return  TRUE;

(5)            }

(6)            return FALSE

 

第二步由频繁项集产生关联规则如下:

l  对每个频繁项集l,产生l的所有非空子集。

l  对l的每个非空子集s,如果,则产生规则“s(l-s)”。min_conf是最小置信度。

 

限制条件

算法只能处理单维、单层的种类字段。

这个方法要求多次扫描可能很大的交易数据库,这需要很大的I/O负载,因此处理的数据量不能太大。

输出结果

算法输出事务数据库中的关联规则,规则形如AB。

算法优点和缺点

优点:

l  提出了利用Apriori性质挖掘频繁项集产生关联规则的思想,对以后的关联规则算法有深远的影响。

l  提出的Apriori性质大幅压缩了候选项集的大小,提高了性能。

l  可用来提高冰山查询的效率。

缺点:

l  只能处理单维、单层的种类字段

l  可能产生大量的候选集,

l  可能需要重复扫描数据库,I/O负担大。

改进:

对Apriori算法的改进已有许多方法,如散列,事务压缩,划分和选样等,都是基于减少数据扫描次数的思想。但都不如FP-Tree的改进彻底,有效。

 

事务数据库 D

例子

 

处理:假定最小支持计数为2。

L1

根据最小支持度,产生频繁1-项集

第一步:产生频繁项集

 

 

C2

C3

 

 

 

 

 

 

 

 

 

得到频繁项集:{{1};{2};{3};{5};{1, 3};{2, 3};{2, 5};{3, 5};{2, 3, 5}}

 

第2步:由频繁项集产生关联规则,假定最小置信度为70%

1)        对频繁项集{1, 3},它的非空子集为{1},{3}。

对{1},;所以输出规则1→3;

对{3},;所以不输出规则;

2)        对频繁项集{2, 3},它的非空子集为{2},{3}。

对{2},;所以不输出规则;

对{3},;所以不输出规则;

3)        对频繁项集{2, 5},它的非空子集为{2},{5}。

对{2},;所以输出规则2→5;

对{5},;所以输出规则5→2;

4)        对频繁项集{3, 5},它的非空子集为{3},{5}。

对{3},;所以不输出规则;

对{5},;所以输出规则;

5)        对频繁项集{2,3, 5},它的非空子集为{2},{3},{5},{2, 3},{2, 5},{3, 5}。

对{2},;所以不输出规则;

对{3},;所以不输出规则;

对{5},;所以输出规则;

对{2,3},;所以输出规则2∧3→5;

对{2,5},;所以不输出规则;

对{3,5},;所以输出规则3∧5→2;

 

得到关联规则1→3;2→5;5→2;2∧3→5;3∧5→2。

C3

L1