机器学习:决策树

 本文根据 决策树DecisionTree(附代码实现) - 知乎 (zhihu.com)这篇文章为基础进行学习,并且给出自己的总结

1.什么是决策树

        决策树是一种基于树结构的有监督学习算法,用于解决分类和回归问题。它通过建立一棵树来对数据进行划分和预测,每个非叶子节点表示一个特征维度上的测试,每个叶子节点表示一个类别或一个数值。

2.如何决策?

        对一个东西进行分类和回归,首先就需要了解,我们是根据什么东西来判断它是什么?

              1.信息熵        

                        它可以衡量一个事件的不确定性或者说随机性。熵越大,数据的不确定性就越大。                  熵越小,数据的不确定性就越小,也就是越确定。

              所以我们在做决策的时候要想办法将上述的H(X)弄到最小

                使用代码实现我们这个公式

def entropy(y_label):
    counter = Counter(y_label)
    ent = 0.0
    for num in counter.values():
        p = num / len(y_label)
        ent += -p * log(p)
    return ent

3.划分数据集

        为什么要划分数据集呢?

                划分数据集的目的是为了在构建决策树时,选择最优的特征进行划分,使得在该特征下          不同类别的样本尽可能地被分离到不同子树中,同时保证同一子树中的类别尽量相同,从而            提高决策树的分类或回归性能,下面提供如何划分,和划分一次的代码。

def split(x_data, y_label, dimension, value):
    index_left = (x_data[:,dimension] <= value)
    index_right = (x_data[:,dimension] > value)
    return x_data[index_left],x_data[index_right]
           ,y_label[index_left],y_label[index_right]

def one_split(x_data, y_label):
    
    best_entropy = float('inf')
    best_dimension = -1
    best_value = -1
    
    for d in range(x_data.shape[1]):
        sorted_index = np.argsort(x_data[:, d])
        for i in range(1,len(x_data)):
            if x_data[sorted_index[i], d] != x_data[sorted_index[i - 1], d]:
                value = (x_data[sorted_index[i], d] + x_data[sorted_index[i-1], d]) / 2
                x_left, x_right, y_left, y_right = split(x_data, y_label, d, value)
                
                p_left = len(x_left) / len(x_data)
                p_right = len(x_right) / len(x_data)
                
                ent = p_left * entropy(y_left) + p_right * entropy(y_right)
                if ent < best_entropy:
                    best_entropy = ent
                    best_dimension = d
                    best_value = value
    return best_entropy, best_dimension, best_value

 解释一下其中比较关键的几行代码

        sorted_index = np.argsort(x_data[:, d])

这个arrgsort是numpy中的一个排列数组的函数,并且将他们的原来位置记作一个数组返回给sorted_index。

举个简单的例子【1,2,3,4,6,5】

用完那个函数后 sorted_index[5] = 4    sorted_index[4] = 5

    if x_data[sorted_index[i], d] != x_data[sorted_index[i - 1], d]:

 这个是避免相同数据作为划分点,提高算法效率。

所以划分数据集的目的是对我们已有的数据进行降噪处理,让我们训练得出的东西更具有适用性。

4.建立树

        通过将父节点和子节点关联起来组成了树,大概结构长这样

 以下是通过python的代码实现的

class Node:
    def __init__(self,x_data, y_label, dimension, value):
        self.x_data = x_data
        self.y_label = y_label
        self.dimension = dimension
        self.value = value
        self.left = None
        self.right = None

class DTree:
    def __init__(self):
        self.root = None
    
    def fit(self,x_train, y_train):
        def entropy(y_label):
            counter = Counter(y_label)
            ent = 0.0
            for num in counter.values():
                p = num / len(y_label)
                ent += -p * log(p)
            return ent
        
        def one_split(x_data, y_label):

            best_entropy = float('inf')
            best_dimension = -1
            best_value = -1

            for d in range(x_data.shape[1]):
                sorted_index = np.argsort(x_data[:, d])
                for i in range(1,len(x_data)):
                    if x_data[sorted_index[i], d] != x_data[sorted_index[i - 1], d]:
                        value = (x_data[sorted_index[i], d] + x_data[sorted_index[i-1], d]) / 2
                        x_left, x_right, y_left, y_right = split(x_data, y_label, d, value)

                        p_left = len(x_left) / len(x_data)
                        p_right = len(x_right) / len(x_data)

                        ent = p_left * entropy(y_left) + p_right * entropy(y_right)
                        if ent < best_entropy:
                            best_entropy = ent
                            best_dimension = d
                            best_value = value
            return best_entropy, best_dimension, best_value
        
        def split(x_data, y_label, dimension, value):
            index_left = (x_data[:,dimension] <= value)
            index_right = (x_data[:,dimension] > value)
            return x_data[index_left], x_data[index_right], y_label[index_left], y_label[index_right]
        
        def create_tree(x_data, y_label):
            ent, dim, value = one_split(x_data, y_label)
            x_left, x_right, y_left, y_right = split(x_data, y_label, dim, value)
            node = Node(x_data, y_label, dim, value)
            if ent < 0.000000001:
                return node
            node.left = create_tree(x_left, y_left)
            node.right = create_tree(x_right, y_right)
            return node

        self.root = create_tree(x_train, y_train)
        
        return self
    
    def predict(self,x_predict):
        def travel(x_data, node):
            p = node
            if x_data[p.dimension] <= p.value and p.left:
                pred = travel(x_data, p.left)
            elif x_data[p.dimension] > p.value and p.right:
                pred = travel(x_data, p.right)
            else:
                counter = Counter(p.y_label)
                pred = counter.most_common(1)[0][0]
            return pred
        
        y_predict = []
        for data in x_predict:
            y_pred = travel(data, self.root)
            y_predict.append(y_pred)
        return np.array(y_predict)
    
    def score(self,x_test,y_test):
        y_predict = self.predict(x_test)
        return np.sum(y_predict == y_test) / len(y_predict)
    
    def __repr__(self):
        return "DTree(criterion='entropy')"

5.个人总结

        在我看来决策树就像是做选择题,对于基于的数据根据提特性不断的选择,就类似于不断的if else ,来一层层判断最后结果

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值