决策树--从原理到实现

算算有相当一段时间没写blog了,主要是这学期作业比较多,而且我也没怎么学新的东西

接下来打算实现一个小的toy lib:DML,同时也回顾一下以前学到的东西

当然我只能保证代码的正确性,不能保证其效率啊~~~~~~

之后我会陆续添加进去很多代码,可以供大家学习的时候看,实际使用还是用其它的吧大笑

================================================================================

一.引入

决策树基本上是每一本机器学习入门书籍必讲的东西,其决策过程和平时我们的思维很相似,所以非常好理解,同时有一堆信息论的东西在里面,也算是一个入门应用,决策树也有回归和分类,但一般来说我们主要讲的是分类,方便理解嘛。

虽然说这是一个很简单的算法,但其实现其实还是有些烦人,因为其feature既有离散的,也有连续的,实现的时候要稍加注意

          (不同特征的决策,图片来自【1】)

O-信息论的一些point:

             然后加入一个叫信息增益的东西:
             □.信息增益:(information gain)
                                 g(D,A) = H(D)-H(D|A)
                                 表示了特征A使得数据集D的分类不确定性减少的程度
             □.信息增益比:(information gain ratio)
                                  g‘(D,A)=g(D,A) / H(D)
             □.基尼指数:
              
                        
                         

二.各种算法

1.ID3

ID3算法就是对各个feature信息计算信息增益,然后选择信息增益最大的feature作为决策点将数据分成两部分

                然后再对这两部分分别生成决策树。

                 图自【1】

       

2.C4.5

                C4.5与ID3相比其实就是用信息增益比代替信息增益,应为信息增益有一个缺点:

                       信息增益选择属性时偏向选择取值多的属性

                算法的整体过程其实与ID3差异不大:图自【2】

                 

3.CART

CART(classification and regression tree)的算法整体过程和上面的差异不大,然是CART的决策是二叉树的

每一个决策只能是“是”和“否”,换句话说,即使一个feature有多个可能取值,也只选择其中一个而把数据分类

两部分而不是多个,这里我们主要讲一下分类树,它用到的是基尼指数:

图自【2】

三.代码及实现

                  好吧,其实我就想贴贴代码而已……本代码在https://github.com/justdark/dml/tree/master/dml/DT

                  纯属toy~~~~~实现的CART算法:

                 

[python]  view plain copy
  1. from __future__ import division  
  2. import numpy as np  
  3. import scipy as sp  
  4. import pylab as py  
  5. def pGini(y):  
  6.         ty=y.reshape(-1,).tolist()  
  7.         label = set(ty)  
  8.         sum=0  
  9.         num_case=y.shape[0]  
  10.         #print y  
  11.         for i in label:  
  12.             sum+=(np.count_nonzero(y==i)/num_case)**2  
  13.         return 1-sum  
  14.       
  15. class DTC:  
  16.     def __init__(self,X,y,property=None):  
  17.         ''''' 
  18.             this is the class of Decision Tree 
  19.             X is a M*N array where M stands for the training case number 
  20.                                    N is the number of features 
  21.             y is a M*1 vector 
  22.             property is a binary vector of size N 
  23.                 property[i]==0 means the the i-th feature is discrete feature,otherwise it's continuous 
  24.                 in default,all feature is discrete 
  25.                  
  26.         '''  
  27.         ''''' 
  28.             I meet some problem here,because the ndarry can only have one type 
  29.             so If your X have some string parameter,all thing will translate to string 
  30.             in this situation,you can't have continuous parameter 
  31.             so remember: 
  32.             if you have continous parameter,DON'T PUT any STRING IN X  !!!!!!!! 
  33.         '''  
  34.         self.X=np.array(X)  
  35.         self.y=np.array(y)  
  36.         self.feature_dict={}  
  37.         self.labels,self.y=np.unique(y,return_inverse=True)  
  38.         self.DT=list()  
  39.         if (property==None):  
  40.             self.property=np.zeros((self.X.shape[1],1))  
  41.         else:  
  42.             self.property=property  
  43.               
  44.         for i in range(self.X.shape[1]):  
  45.             self.feature_dict.setdefault(i)  
  46.             self.feature_dict[i]=np.unique(X[:,i])  
  47.   
  48.         if (X.shape[0] != y.shape[0] ):  
  49.             print "the shape of X and y is not right"  
  50.               
  51.         for i in range(self.X.shape[1]):  
  52.             for j in self.feature_dict[i]:  
  53.                 pass#print self.Gini(X,y,i,j)  
  54.         pass  
  55.   
  56.     def Gini(self,X,y,k,k_v):  
  57.         if (self.property[k]==0):  
  58.             #print X[X[:,k]==k_v],'dasasdasdasd'  
  59.             #print X[:,k]!=k_v  
  60.             c1 = (X[X[:,k]==k_v]).shape[0]  
  61.             c2 = (X[X[:,k]!=k_v]).shape[0]  
  62.             D = y.shape[0]  
  63.             return c1*pGini(y[X[:,k]==k_v])/D+c2*pGini(y[X[:,k]!=k_v])/D  
  64.         else:  
  65.             c1 = (X[X[:,k]>=k_v]).shape[0]  
  66.             c2 = (X[X[:,k]<k_v]).shape[0]  
  67.             D = y.shape[0]  
  68.             #print c1,c2,D  
  69.             return c1*pGini(y[X[:,k]>=k_v])/D+c2*pGini(y[X[:,k]<k_v])/D  
  70.         pass  
  71.     def makeTree(self,X,y):  
  72.         min=10000.0  
  73.         m_i,m_j=0,0  
  74.         if (np.unique(y).size<=1):  
  75.   
  76.             return (self.labels[y[0]])  
  77.         for i in range(self.X.shape[1]):  
  78.             for j in self.feature_dict[i]:  
  79.                 p=self.Gini(X,y,i,j)  
  80.                 if (p<min):  
  81.                     min=p  
  82.                     m_i,m_j=i,j  
  83.           
  84.           
  85.   
  86.         if (min==1):  
  87.             return (y[0])  
  88.         left=[]  
  89.         righy=[]  
  90.         if (self.property[m_i]==0):  
  91.             left = self.makeTree(X[X[:,m_i]==m_j],y[X[:,m_i]==m_j])  
  92.             right = self.makeTree(X[X[:,m_i]!=m_j],y[X[:,m_i]!=m_j])  
  93.         else :  
  94.             left = self.makeTree(X[X[:,m_i]>=m_j],y[X[:,m_i]>=m_j])  
  95.             right = self.makeTree(X[X[:,m_i]<m_j],y[X[:,m_i]<m_j])  
  96.         return [(m_i,m_j),left,right]  
  97.     def train(self):  
  98.         self.DT=self.makeTree(self.X,self.y)  
  99.         print self.DT  
  100.           
  101.     def pred(self,X):  
  102.         X=np.array(X)  
  103.             
  104.         result = np.zeros((X.shape[0],1))  
  105.         for i in range(X.shape[0]):  
  106.             tp=self.DT  
  107.             while ( type(tp) is  list):  
  108.                 a,b=tp[0]  
  109.                   
  110.                 if (self.property[a]==0):  
  111.                     if (X[i][a]==b):  
  112.                         tp=tp[1]  
  113.                     else:  
  114.                         tp=tp[2]  
  115.                 else:  
  116.                     if (X[i][a]>=b):  
  117.                         tp=tp[1]  
  118.                     else:  
  119.                         tp=tp[2]  
  120.             result[i]=self.labels[tp]  
  121.         return result  
  122.         pass  
  123.       

               这个maketree让我想起了线段树………………代码里的变量基本都有说明

试验代码:

  

[python]  view plain copy
  1. from __future__ import division  
  2. import numpy as np  
  3. import scipy as sp  
  4. from dml.DT import DTC  
  5. X=np.array([  
  6. [0,0,0,0,8],  
  7. [0,0,0,1,3.5],  
  8. [0,1,0,1,3.5],  
  9. [0,1,1,0,3.5],  
  10. [0,0,0,0,3.5],  
  11. [1,0,0,0,3.5],  
  12. [1,0,0,1,3.5],  
  13. [1,1,1,1,2],  
  14. [1,0,1,2,3.5],  
  15. [1,0,1,2,3.5],  
  16. [2,0,1,2,3.5],  
  17. [2,0,1,1,3.5],  
  18. [2,1,0,1,3.5],  
  19. [2,1,0,2,3.5],  
  20. [2,0,0,0,10],  
  21. ])  
  22.   
  23.   
  24. y=np.array([  
  25. [1],  
  26. [0],  
  27. [1],  
  28. [1],  
  29. [0],  
  30. [0],  
  31. [0],  
  32. [1],  
  33. [1],  
  34. [1],  
  35. [1],  
  36. [1],  
  37. [1],  
  38. [1],  
  39. [1],  
  40. ])  
  41. prop=np.zeros((5,1))  
  42. prop[4]=1  
  43. a=DTC(X,y,prop)  
  44. a.train()  
  45. print a.pred([[0,0,0,0,3.0],[2,1,0,1,2]])  

可以看到可以学习出一个决策树:


展示出来大概是这样:注意第四个参数是连续变量



               


四.reference

           【1】:《机器学习》 -mitchell,卡耐基梅龙大学
           【2】:《统计学习方法》-李航
转自:http://blog.csdn.net/pi9nc/article/details/27713115

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值