【决策树】什么!他只用Numpy和List实现决策树

什么是决策树

决策树是通过树结构进行决策的,非常像人在对某件事进行决策的过程。例如:我们要买房子,首先我们要考虑买“新房”还是“二手房”,如果是”新房“,那接下来看”交通是否便利“,如果便利,我们再判断下一个条件,最后我们决定“买它!”。买房或者不买房,我们可以看成一种而分类问题,那么我们可以通过树的结构去表现出咱们的决策过程。
举个例子:
我要买房子,并且这个房子必须是学区房,那么我们买房子最重要的因素就是这个房子是否靠近学校,那么我再考虑我的存款是否能负担得起首付,假设我们只考虑这两点,那么我们决策过程能可视化成下面这种图:
在这里插入图片描述
现在我们有一处房源:

区域售价
某某某高中旁边100万

根据这一处的房源,我们来进行决策,首先我们看区域,高中旁边,那么我们在上面这种图中就满足了区域的要求,我们走向售价方面,这个房子售价100万,我手里有200万,那么我们肯定会进行交易,把这房子拿下来。但是上图的二叉树是我们已经构建好的,而在实际分类的过程中,我们需要根据基本流程把决策树构建出来。

基本流程

  1. 输入数据集
  2. 构建根节点,将所有的数据放在根节点。
  3. 从特征集中选择最优特征。
  4. 进行判断:如果子集已经能够被基本正确分类,构建叶子结点,到5。
    如果还有子集不能被基本分类正确,特征集中去除已选的最有特征,回到3
  5. 输出决策树

看了上述过程,最懵逼的应该是如果从特征集中选择最优特征,到底我是先看看自己有没有钱买得起房子,还是先看这个房子到底是不是学区房。显然,决策树学习的算法是一个递归地选择最优特征,最重要的就是如何选择最优特征。

最优特征

下面就是看公式,了解公式的过程啦。

信息增益

“熵”也称“信息熵”是表示随机变量不确定性的度量。
X X X是一个取有限个值得离散随机变量,其概率分布为:
P ( X = X i ) = p i , i = 1 , 2 , … , n P(X=X_i) = p_i, i=1,2,\dots,n P(X=Xi)=pi,i=1,2,,n
则随机变量 X X X的熵表示为:
H ( x ) = − ∑ i = 1 n p i log ⁡ p i i f   p i = 0 , 0 log ⁡ 0 = 0 H(x) = - \sum_{i=1}^np_i\log pi \qquad if \ p_i = 0,0\log 0 = 0 H(x)=i=1npilogpiif pi=0,0log0=0
熵越大,随机变量的不确定性就越大。

条件熵 H ( Y ∣ X ) H(Y|X) H(YX)表示在已知随机变量 X X X的条件下随机变量 Y Y Y的不确定性
H ( Y ∣ X ) = ∑ i = 1 n p i H ( Y ∣ X = x i ) p i = P ( X = x i ) , i = 1 , 2 , … , n (1) H(Y|X) = \sum_{i=1}^np_iH(Y|X=x_i) \qquad p_i=P(X=x_i),i=1,2,\dots,n \tag{1} H(YX)=i=1npiH(YX=xi)pi=P(X=xi),i=1,2,,n(1)
“信息增益”:特征 A A A对训练数据集 D D D的信息增益 g ( D , A ) g(D,A) g(D,A),定义为集合 D D D的经验熵 H ( D ) H(D) H(D)与特征 A A A给定条件下 D D D的经验条件熵 H ( D ∣ A ) H(D|A) H(DA)之差,即
g ( D , A ) = H ( D ) − H ( D ∣ A ) (2) g(D,A) = H(D) - H(D|A) \tag{2} g(D,A)=H(D)H(DA)(2)
我们把训练数据集 D D D的样本容量设为 ∣ D ∣ |D| D,设有 K K K个类 D k ,   k = 1 , 2 , … , K ,   ∣ D k ∣ D_k, \ k=1,2,\dots,K, \ |D_k| Dk, k=1,2,,K, Dk为属于类 D k D_k Dk的样本个数,训练数据集 D D D的熵为:
H ( D ) = − ∑ i = 1 K ∣ D k ∣ ∣ D ∣ log ⁡ 2 ∣ D k ∣ ∣ D ∣ (3) H(D) = - \sum_{i=1}^K \frac{|D_k|}{|D|}\log_2 \frac{|D_k|}{|D|} \tag{3} H(D)=i=1KDDklog2DDk(3)
设特征 A A A n n n个不同的取值 { a 1 , a 2 , … , a n } \{a_1,a_2,\dots,a_n \} {a1,a2,,an},根据特征 A A A的取值将 D D D划分为 n n n个子集 D 1 , D 2 , … , D n D_1,D_2,\dots,D_n D1,D2,,Dn ∣ D i ∣ |D_i| Di D i D_i Di的样本个数,记子集 D i D_i Di中属于类 D k D_k Dk的样本集合为 D i k D_{ik} Dik ∣ D i k ∣ |D_{ik}| Dik D i k D_{ik} Dik的样本个数,那么经验条件熵 H ( D ∣ A ) H(D|A) H(DA)为:
H ( D ∣ A ) = ∑ i = 1 n ∣ D i ∣ ∣ D ∣ H ( D i ) = − ∑ i = 1 n ∣ D i ∣ ∣ D ∣ ∑ k = 1 K ∣ D i k ∣ ∣ D i ∣ log ⁡ 2 ∣ D i k ∣ ∣ D i ∣ (4) H(D|A) = \sum_{i=1}^n \frac{|D_i|}{|D|}H(D_i) = -\sum_{i=1}^n \frac{|D_i|}{|D|} \sum_{k=1}^K \frac{|D_{ik}|}{|D_i|} \log_2 \frac{|D_{ik}|}{|D_i|} \tag{4} H(DA)=i=1nDDiH(Di)=i=1nDDik=1KDiDiklog2DiDik(4)
信息增益为:
g ( D , A ) = − ∑ i = 1 K ∣ D k ∣ ∣ D ∣ log ⁡ ∣ D k ∣ ∣ D ∣ + ∑ i = 1 n ∣ D i ∣ ∣ D ∣ ∑ k = 1 K ∣ D i k ∣ ∣ D i ∣ log ⁡ 2 ∣ D i k ∣ ∣ D i ∣ (5) g(D,A) = - \sum_{i=1}^K \frac{|D_k|}{|D|}\log \frac{|D_k|}{|D|} + \sum_{i=1}^n \frac{|D_i|}{|D|} \sum_{k=1}^K \frac{|D_{ik}|}{|D_i|} \log_2 \frac{|D_{ik}|}{|D_i|} \tag{5} g(D,A)=i=1KDDklogDDk+i=1nDDik=1KDiDiklog2DiDik(5)

经验熵 H ( D ) H(D) H(D)表示对数据集 D D D进行分类的不确定性。而经验条件熵 H ( D ∣ A ) H(D|A) H(DA)表示在特征 A A A给定的条件下对数据集 D D D进行分类的不确定性。那么他们的差,即信息增益,就表示由于特征 A A A而使得对数据集 D D D的分类的不确定性减少的程度。信息增益大的特征具有更强的分类能力。

信息增益算法

(1)输入训练数据集D和特征A
(2)计算数据集D的经验熵 H ( D ) H(D) H(D)
H ( D ) = − ∑ i = 1 K ∣ D k ∣ ∣ D ∣ log ⁡ ∣ D k ∣ ∣ D ∣ H(D) = - \sum_{i=1}^K \frac{|D_k|}{|D|}\log \frac{|D_k|}{|D|} H(D)=i=1KDDklogDDk
(3)计算特征 A A A对数据集 D D D的经验条件熵 H ( D ∣ A ) H(D|A) H(DA)
H ( D ∣ A ) = − ∑ i = 1 n ∣ D i ∣ ∣ D ∣ ∑ k = 1 K ∣ D i k ∣ ∣ D i ∣ log ⁡ 2 ∣ D i k ∣ ∣ D i ∣ H(D|A) = -\sum_{i=1}^n \frac{|D_i|}{|D|} \sum_{k=1}^K \frac{|D_{ik}|}{|D_i|} \log_2 \frac{|D_{ik}|}{|D_i|} H(DA)=i=1nDDik=1KDiDiklog2DiDik
(4)计算信息增益
g ( D , A ) = H ( D ) − H ( D ∣ A ) g(D,A) = H(D) - H(D|A) g(D,A)=H(D)H(DA)
(5)输出特征 A A A对训练集 D D D的信息收益 g ( D , A ) g(D,A) g(D,A)

举个例子说明一下

贷款申请样本数据,这个数据我们引用自李航的《统计学习方法》,我们根据信息增益准则选择最优特征。
table1

  1. 首先我们计算经验熵 H ( D ) H(D) H(D)
    我们最后要决策的是“是否同意贷款申请”,所以我们是二分类问题,根据“类别”这一列,我们可以统计出来“是”的概率分布为 9 15 \dfrac{9}{15} 159,“否”的概率分布为 6 15 \dfrac{6}{15} 156。那我们可以求出经验熵 H ( D ) H(D) H(D)
    H ( D ) = − 9 15 log ⁡ 2 9 15 − 6 15 log ⁡ 2 6 15 = 0.971 H(D) = -\frac{9}{15} \log_2 \frac{9}{15} -\frac{6}{15} \log_2 \frac{6}{15} = 0.971 H(D)=159log2159156log2156=0.971

  2. 计算各特征对数据集 D D D的信息增益。这里我们可以从表格中知道有4个特征,分别是“年龄”,“有工作”,“有自己的房子”和“信贷情况”。
    (1)对于“年龄”特征
    对于“年龄”这一特征分别有“青年”,“中年”,“老年”这三种情况,并且概率分布都为 5 15 \dfrac{5}{15} 155。“青年”、"中年"和“老年”在“类别”为是的比例分别为 2 5 \dfrac{2}{5} 52 3 5 \dfrac{3}{5} 53 4 5 \dfrac{4}{5} 54。“年龄”特征对数据集 D D D的信息增益为:
    g ( D , 年 龄 ) = H ( D ) − [ 5 15 H ( 青 年 ) + 5 15 H ( 中 年 ) + 5 15 H ( 老 年 ) ] = 0.971 − [ 5 15 ( − 2 5 log ⁡ 2 2 5 − 3 5 log ⁡ 2 3 5 ) + 5 15 ( − 3 5 log ⁡ 2 3 5 − 2 5 log ⁡ 2 2 5 ) + 5 15 ( − 4 5 log ⁡ 2 4 5 − 1 5 log ⁡ 2 1 5 ) ] = 0.971 − 0.888 = 0.083 \begin{aligned} g(D, 年龄) &= H(D) - [\frac{5}{15}H(青年)+\frac{5}{15}H(中年)+\frac{5}{15}H(老年)] \\ &= 0.971 - [\frac{5}{15}(-\frac{2}{5} \log_2 \frac{2}{5} - \frac{3}{5} \log_2 \frac{3}{5}) + \frac{5}{15}(-\frac{3}{5} \log_2 \frac{3}{5} - \frac{2}{5} \log_2 \frac{2}{5}) \\& + \frac{5}{15}(-\frac{4}{5} \log_2 \frac{4}{5} - \frac{1}{5} \log_2 \frac{1}{5})] \\ &=0.971 - 0.888 \\ &= 0.083 \end{aligned} g(D,)=H(D)[155H()+155H()+155H()]=0.971[155(52log25253log253)+155(53log25352log252)+155(54log25451log251)]=0.9710.888=0.083
    (2)类似的,我们可以求出其他特征的信息增益,这里我们分别将“有工作”,“有自己的房子”和“信贷情况”设为 A 2 , A 3 , A 4 A_2,A_3,A_4 A2,A3,A4,其样本子集设为 D 1 , D 2 , D 3 D_1,D_2,D_3 D1,D2,D3
    g ( D , A 2 ) = H ( D ) − [ 5 15 H ( D 1 ) + 10 15 H ( D 2 ) ] = 0.971 − [ 5 15 × 0 + 10 15 ( − 4 10 log ⁡ 2 4 10 − 6 10 log ⁡ 2 6 10 ) ] = 0.324 \begin{aligned} g(D,A_2) &= H(D) - [\frac{5}{15}H(D_1) + \frac{10}{15}H(D_2)] \\ & = 0.971 - [\frac{5}{15} \times 0 + \frac{10}{15}(-\frac{4}{10} \log_2 \frac{4}{10} - \frac{6}{10} \log_2 \frac{6}{10})] \\ &= 0.324 \end{aligned} g(D,A2)=H(D)[155H(D1)+1510H(D2)]=0.971[155×0+1510(104log2104106log2106)]=0.324

g ( D , A 3 ) = 0.971 − [ 6 15 × 0 + 9 15 ( − 3 9 log ⁡ 2 3 9 − 6 9 log ⁡ 2 6 9 ) ] = 0.971 − 0.551 = 0.420 \begin{aligned} g(D,A_3) &= 0.971 - [\frac{6}{15} \times 0 + \frac{9}{15}(-\frac{3}{9} \log_2 \frac{3}{9} - \frac{6}{9} \log_2 \frac{6}{9})] \\ &= 0.971 - 0.551 \\ &= 0.420 \\ \end{aligned} g(D,A3)=0.971[156×0+159(93log29396log296)]=0.9710.551=0.420

g ( D , A 4 ) = 0.971 − [ 5 15 ( − 1 5 log ⁡ 2 1 5 − 4 5 log ⁡ 2 4 5 ) + 6 15 ( − 4 6 log ⁡ 2 4 6 − 2 6 log ⁡ 2 2 6 ) + 4 15 ( − 6 6 log ⁡ 2 6 6 − 0 log ⁡ 2 0 ) ] = 0.363 \begin{aligned} g(D,A_4) &= 0.971 - [\frac{5}{15}(-\frac{1}{5}\log_2\frac{1}{5}-\frac{4}{5}\log_2\frac{4}{5}) \\&+ \frac{6}{15}(-\frac{4}{6}\log_2\frac{4}{6}-\frac{2}{6}\log_2\frac{2}{6}) + \frac{4}{15}(-\frac{6}{6}\log_2\frac{6}{6}-0\log_20)] \\&= 0.363 \end{aligned} g(D,A4)=0.971[155(51log25154log254)+156(64log26462log262)+154(66log2660log20)]=0.363
(3)最后,比较各特征的信息增益值。因为信息增益值大的特征更具有分类能力,由于特征 A 3 A_3 A3(有自己的房子)的信息增益值最大,所以选择特征 A 3 A_3 A3作为最优特征。

信息增益比

特征 A A A对训练数据集 D D D的信息增益比 g R ( D , A ) g_R(D,A) gR(D,A)定义为其信息增益 g ( D , A ) g(D,A) g(D,A)与训练数据集 D D D的经验熵 H ( D ) H(D) H(D)之比:
g R ( D , A ) = g ( D , A ) H ( D ) g_R(D,A)=\frac {g(D,A)}{H(D)} gR(D,A)=H(D)g(D,A)
实际上,信息增益对可取值数目较多的属性有所偏好,为减少这种偏好可能带来的不利影响,我们使用“信息增益比”也就是“增益率”来选择最优划分属性。信息增益比对可取值数目较少的属性有所偏好。

基尼指数

分类问题中,假设有 K K K个类,样本点属于第 k k k类的概率为 p k p_k pk,则概率分布的基尼指数定义为:
G i n i ( p ) = ∑ k = 1 K p k ( 1 − p k ) = 1 − ∑ k = 1 K p k 2 Gini(p) = \sum_{k=1}^K p_k(1-p_k) = 1- \sum_{k=1}^K p_k^2 Gini(p)=k=1Kpk(1pk)=1k=1Kpk2
对于二分类问题,若样本中第1类的概率为 p p p,则概率分布的基尼指数为:
G i n i ( D ) = 2 p ( 1 − p ) Gini(D) = 2p(1-p) Gini(D)=2p(1p)
如果样本集合 D D D根据特征 A A A是否取某一可能值 a a a被分割称 D 1 D_1 D1 D 2 D_2 D2两个部分,即:
D 1 = { ( x , y ) ∈ D ∣ A ( x ) = a } , D 2 = D − D 1 D_1 = \{ (x,y) \in D| A(x) = a\},\qquad D_2 = D - D_1 D1={(x,y)DA(x)=a},D2=DD1
在特征 A A A的条件下,集合 D D D的基尼指数定义为
G i n i ( D , A ) = ∣ D 1 ∣ ∣ D ∣ G i n i ( D 1 ) + ∣ D 2 ∣ ∣ D ∣ G i n i ( D 2 ) Gini(D,A) = \frac{|D_1|}{|D|}Gini(D_1)+ \frac{|D_2|}{|D|}Gini(D_2) Gini(D,A)=DD1Gini(D1)+DD2Gini(D2)

ID3 算法

在这里插入图片描述
程序是根据上面的流程进行编写的,变量命名也根据公式来的。我们这里没有加入阈值,只是通过python对ID3算法进行简单的实现,并通过几个测试数据对决策树进行测试。
整个算法中,我们只用到了numpy库,树的结构我们通过list进行构建。

'''
因为我们的问题是二分类问题,所以我们树的结构应该是二叉树,
这里我们定义构造二叉树和对左右结点以及根结点进行赋值
其中`Bintree`为构建树,`set_root` `set_left` `set_right`为设置根结点和左右结点,
`root` `left` `right`为访问结点。
'''
def Bintree(data, left=None, right=None):

    btree = [data, left, right]

    return btree
    
# 设置结点
def set_root(btree, data):

    btree[0] = data

def set_left(btree, left):

    btree[1] = left

def set_right(btree, right):

    btree[2] = right

# 读取结点
def root(btree):

    return btree[0]

def left(btree):

    return btree[1]

def right(btree):

    return btree[2]

'''
对于ID3算法来说,最重要的就是求信息增益,
在代码中,尽量通过矩阵运算来减少for循环的使用,求信息增益的代码如下:
在代码中我们导入了numpy库,取了别名为np
import numpy as np
'''
def get_gain(data, features):

    m = data.shape[0]  # 数据样本数

    n = data.shape[1]  # 特征数

    Ck = np.bincount(data[:, n-1])

    Hd = round(-np.sum(Ck/m * np.log2(Ck/m)), 3)  # 经验熵H(D)

    gain = []  # 信息增益
    
	'''
	 np.bincount 是用来统计矩阵中相同元素的个数. 
	 features为特征集合,在程序中我们用0 1 2 3 来代表数据集中的四个特征
	'''
    for i in features:

        Di = np.bincount(data[:, i])  # 特征子集的样本数

        Hdi = []

        for k in range(len(Di)):

            index = np.where(data[:, i] == k)

            Dik = np.bincount(data[:, n-1][index])  # 找出"类别"中为1的数量,样本子集中允许放贷的样本量

            if Dik[0] == 0:

                hdi = -(Dik[1]/Di[k] * np.log2(Dik[1]/Di[k]))

            elif len(Dik) == 2 and Dik[1] == 0:

                hdi = -(Dik[0]/Di[k] * np.log2(Dik[0]/Di[k]))

            else:

                hdi = -np.sum(Dik/Di[k] * np.log2(Dik/Di[k]))

            Hdi.append(hdi)

        Hda = round(np.sum(Di/m * Hdi), 3)

        g = round(Hd - Hda, 3)  # 计算信息增益

        gain.append(g)

    return gain
'''
建造决策树的函数
'''
def Buid_tree(data, features):

    if len(features) != 0:

        gain = get_gain(data, features)

        gain = np.array([gain])

        Max_index = np.where(gain == np.max(gain))  # 找到信息增益最大值的位置



        # 最大信息增益的位置

        x = Max_index[0].tolist()[0]

        y = Max_index[1].tolist()[0]



        btree = Bintree(features[y])  # 创建根结点

        lable = []  # 标记是否对子集进行正确的分类

        l_r = []   # 标记左叶结点还是右叶结点

        inx = []  # 存储每个子特征的索引

        for i in range(len(np.bincount(data[:, y]))):   # 该特征下,每个子特征的分类情况

            index = np.where(data[:, y] == i)  # 每个子特征的索引

            inx.append(index)

            judge_mat = data[:, data.shape[1]-1][index]  # 每个子特征是否进行放贷的情况

			# 进行判断,添加标记,lable中1代表子集中都分类正确,0代表还有没有正确分类的子集
			# l_r中1代表右结点,0代表左结点

            if len(np.where(judge_mat == 1)[0]) == len(judge_mat):

                lable.append(1)

                l_r.append(1)

            elif len(np.where(judge_mat == 0)[0]) == len(judge_mat):

                lable.append(1)

                l_r.append(0)

            else:

                lable.append(0)

                l_r.append(None)



        # 判断是否属于同一类,如果长度一样,说明里面只有一类

        features.remove(features[y])

        if len(np.where(np.array(lable) == 1)[0]) == len(lable):

            set_left(btree, "No")

            set_right(btree, "Yes")

        elif len(np.where(np.array(lable) == 1)) != 0:

            for i in range(len(lable)):

                if lable[i] == 1 and l_r[i] == 0:

                    data = np.delete(data, inx[i], axis=0)

                    set_right(btree, Buid_tree(data, features))

                    set_left(btree, "No")

                elif lable[i] == 1 and l_r[i] == 1:

                    data = np.delete(data, inx[i], axis=0)

                    set_right(btree, "Yes")

                    set_left(btree, Buid_tree(data, features))

                else:

                    continue



        else:
		# 没有进行完全分类的情况
            data1 = np.delete(data, inx[0], axis=0)

            data2 = np.delete(data, inx[1], axis=0)

            set_left(btree, Buid_tree(data1, features))

            set_right(btree, Buid_tree(data2, features))



    return btree

下面的部分代码是用来进行测试:

def search(test, tree):

    for data in test:

        btree = tree

        while True:

            feature = root(btree)

            if data[feature] == 0:

                btree = left(btree)

                if isinstance(btree, str):

                    print(btree)

                    break

            else:

                btree = right(btree)

                if isinstance(btree, str):

                    print(btree)

                    break

全部代码

import numpy as np

# 生成数据集
'''
年龄: 0-青年 1-中年 2-老年
有工作:0-否 1-是
有自己的房子 0-否 1-是
信贷情况 0-一般 1-好 2-非常好
类别 0-不放贷 1-放贷
本问题为二分类问题
'''
def Bintree(data, left=None, right=None):
    btree = [data, left, right]
    return btree

def set_root(btree, data):
    btree[0] = data

def set_left(btree, left):
    btree[1] = left

def set_right(btree, right):
    btree[2] = right

def root(btree):
    return btree[0]

def left(btree):
    return btree[1]

def right(btree):
    return btree[2]


def get_gain(data, features):
    m = data.shape[0]  # 数据样本数
    n = data.shape[1]  # 特征数
    Ck = np.bincount(data[:, n-1])
    Hd = round(-np.sum(Ck/m * np.log2(Ck/m)), 3)  # 经验熵H(D)
    gain = []  # 信息增益
    for i in features:
        Di = np.bincount(data[:, i])  # 特征子集的样本数
        Hdi = []
        for k in range(len(Di)):
            index = np.where(data[:, i] == k)
            Dik = np.bincount(data[:, n-1][index])  # 找出"类别"中为1的数量,样本子集中允许放贷的样本量
            if Dik[0] == 0:
                hdi = -(Dik[1]/Di[k] * np.log2(Dik[1]/Di[k]))
            elif len(Dik) == 2 and Dik[1] == 0:
                hdi = -(Dik[0]/Di[k] * np.log2(Dik[0]/Di[k]))
            else:
                hdi = -np.sum(Dik/Di[k] * np.log2(Dik/Di[k]))
            Hdi.append(hdi)
        Hda = round(np.sum(Di/m * Hdi), 3)
        g = round(Hd - Hda, 3)  # 计算信息增益
        gain.append(g)
    return gain

def Buid_tree(data, features):
    if len(features) != 0:
        gain = get_gain(data, features)
        gain = np.array([gain])
        Max_index = np.where(gain == np.max(gain))  # 找到信息增益最大值的位置

        # 最大信息赠饮的位置
        x = Max_index[0].tolist()[0]
        y = Max_index[1].tolist()[0]

        btree = Bintree(features[y])  # 创建根结点
        lable = []
        l_r = []   # 标记左叶结点还是右叶结点
        inx = []
        for i in range(len(np.bincount(data[:, y]))):   # 该特征下,每个子特征的分类情况
            index = np.where(data[:, y] == i)  # 每个子特征的索引
            inx.append(index)
            judge_mat = data[:, data.shape[1]-1][index]  # 每个子特征是否进行放贷的情况
            if len(np.where(judge_mat == 1)[0]) == len(judge_mat):  # 分类都为0的情况
                lable.append(1)
                l_r.append(1)
            elif len(np.where(judge_mat == 0)[0]) == len(judge_mat):  # 分类都为1的情况
                lable.append(1)
                l_r.append(0)
            else:
                lable.append(0)
                l_r.append(None)

        # 判断是否属于同一类,如果长度一样,说明里面只有一类
        features.remove(features[y])
        if len(np.where(np.array(lable) == 1)[0]) == len(lable):  # 判断是否都分到一类中
            set_left(btree, "No")
            set_right(btree, "Yes")
        elif len(np.where(np.array(lable) == 1)) != 0:  # 其中有都分到一类的情况
            for i in range(len(lable)):
                if lable[i] == 1 and l_r[i] == 0:
                    data = np.delete(data, inx[i], axis=0)
                    set_right(btree, Buid_tree(data, features))  # 建立右子树
                    set_left(btree, "No")  # 建立叶子节点
                elif lable[i] == 1 and l_r[i] == 1:
                    data = np.delete(data, inx[i], axis=0)
                    set_right(btree, "Yes")  # 建立叶子节点
                    set_left(btree, Buid_tree(data, features))  # 建立左子树
                else:
                    continue

        else: # 都没有分类到一类中
            data1 = np.delete(data, inx[0], axis=0)
            data2 = np.delete(data, inx[1], axis=0)
            set_left(btree, Buid_tree(data1, features))
            set_right(btree, Buid_tree(data2, features))

    return btree

def search(test, tree):
    for data in test:
        btree = tree
        while True:
            feature = root(btree)
            if data[feature] == 0:
                btree = left(btree)
                if isinstance(btree, str):  # 因为叶子节点是“Yes”、“No”所以判断是否为字符类型
                    print(btree)  # 输出叶子结点
                    break
            else:
                btree = right(btree)
                if isinstance(btree, str):
                    print(btree)
                    break

if __name__ == '__main__':
    data_set = np.array([[0, 0, 0, 0, 0],
                         [0, 0, 0, 1, 0],
                         [0, 1, 0, 1, 1],
                         [0, 1, 1, 0, 1],
                         [0, 0, 0, 0, 0],
                         [1, 0, 0, 0, 0],
                         [1, 0, 0, 1, 0],
                         [1, 1, 1, 1, 1],
                         [1, 0, 1, 2, 1],
                         [1, 0, 1, 2, 1],
                         [2, 0, 1, 2, 1],
                         [2, 0, 1, 1, 1],
                         [2, 1, 0, 1, 1],
                         [2, 1, 0, 2, 1],
                         [2, 0, 0, 0, 0]])
    features = np.arange(0, data_set.shape[1]-1).tolist()  # 特征集合
    Tree = Buid_tree(data_set, features)

	#  测试数据集
    test_data = np.array([[1, 1, 1, 2],
                          [2, 1, 0, 1],
                          [1, 0, 0, 0]])
    search(test_data, Tree)
	'''
	 输出结果自行测试喽,自己编写的程序可以跑通,这个程序只是简单的实现决策树,
	 没有进行优化,更换数据集可能会报错。
	'''


参考文献:
【1】李航 《统计学习方法》
【2】周志华《机器学习》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值