机器学习决策树:原理与应用

一、决策树的工作原理:

决策树是一种监督学习算法,主要用于分类问题,也可以用于回归问题。它通过学习数据的特征来构建一个树状模型,这个模型能够用来做预测。以下是决策树工作原理的简单步骤:

1.数据准备:首先,需要准备带有标签(类别)的数据集,数据集中的每个样本都有一个或多个特征和一个目标变量。

2.选择特征:算法选择一个特征作为分割点,这个特征应能最大程度地减少数据的不纯度或增加信息增益。常用的评估标准有信息熵、基尼不纯度等。

3.创建节点:基于选定的特征,数据被分成不同的子集,每个子集对应一个内部节点(决策节点)。

4.分裂过程:这个过程会递归地对每个子集重复以上步骤,直到满足停止条件。

停止条件可能包括:
所有样本属于同一类别
样本数量低于某个阈值
没有更多特征可选
达到预设的最大树深度

5.创建叶子节点:当停止条件满足时,创建叶子节点,分配最常见的类别(对于分类问题)或平均值(对于回归问题)。

6.(更进一步优化)剪枝:为了防止过拟合,决策树可能会进行剪枝,即删除一些非必要的分支,以提高泛化能力。

7.预测:新样本沿着树从根节点到叶节点路径上的决策规则进行分类或回归。

二、决策树的应用场景:

1.分类问题:
        分类问题:
        医学诊断:通过病人的医疗历史、症状和检查结果,预测疾病类型。
        信贷评估:银行和金融机构使用决策树来评估贷款申请人的信用风险。
        邮件过滤:识别垃圾邮件和非垃圾邮件。
        市场细分:确定消费者群体并制定营销策略。

2.风险管理:
        金融风控:分析客户的信用评分、收入、债务等信息,决定是否批准贷款。
        保险业:评估保险索赔的风险等级。

3.客户关系管理:
        客户流失分析:预测客户可能取消订阅或停止购买产品。
        客户满意度:理解影响客户满意度的因素。

三、决策树构建:

ID3:信息增益:

熵(Entropy):事物的不确定性,越不确定,熵越大。一个随机变量X的熵的计算如下:

随机变量均匀分布时,熵达到最大。即均匀分布的不确定性最强。而n类平均分布的熵会小于n+1类平均分布的熵。信息增益越大,说明变量带来的信息越多,即越有用。

C4.5: 信息增益率:

特征熵:特征熵可以用来衡量样本在使用某特征划分后的分布的不确定性。取值数目越多,分割后各取值得到的样本分布得越均匀,则特征熵越大。可以用它作为分母,来惩罚取值多的特征,以纠正ID3的偏好。

信息增益率越大,说明变量带来的信息越多,即越有用。

CART:基尼指数:

Gini指数:衡量一个分割的纯净度。Gini指数越小,说明此分割越纯净,此分割中的绝大部分样本属于同一类。随机抽取两个样本,其类别不一致的概率, 类似于 p(1-p)。

基尼指数越小,说明变量带来的信息越多,即越有用。

四、代码分析:

使用基尼指数构建决策树,但是未成功

思路分析:

1.读取表格数据

2.转化表格数据为矩阵,方便后续计算

3.统计各特征下不同属性的个数

4.计算基尼指数,取最小的特征作为划分依据(只实现到这一步)

5.将划分后的数据存入多叉树,在重复执行3,4两步,直到决策树划分满足停止条件

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt


# 读取data.xlsx文件
def DataSet():
    data = pd.read_excel('data.xlsx')
    return data


# 将data.xlsx文件转化为矩阵
def ChangeData1(data):
    for i in range(data.shape[0]):
        if data[i][1] == '乌黑':
            data[i][1] = 0
        elif data[i][1] == '青绿':
            data[i][1] = 1
        elif data[i][1] == '浅白':
            data[i][1] = 2
        if data[i][2] == '蜷缩':
            data[i][2] = 0
        elif data[i][2] == '稍蜷':
            data[i][2] = 1
        elif data[i][2] == '硬挺':
            data[i][2] = 2
        if data[i][3] == '沉闷':
            data[i][3] = 0
        elif data[i][3] == '浊响':
            data[i][3] = 1
        elif data[i][3] == '清脆':
            data[i][3] = 2
        if data[i][4] == '模糊':
            data[i][4] = 0
        elif data[i][4] == '稍糊':
            data[i][4] = 1
        elif data[i][4] == '清晰':
            data[i][4] = 2
        if data[i][5] == '凹陷':
            data[i][5] = 0
        elif data[i][5] == '稍凹':
            data[i][5] = 1
        elif data[i][5] == '平坦':
            data[i][5] = 2
        if data[i][6] == '软粘':
            data[i][6] = 0
        elif data[i][6] == '硬滑':
            data[i][6] = 1
        if data[i][7] == '否':
            data[i][7] = 0
        elif data[i][7] == '是':
            data[i][7] = 1
    return data


# 统计各属性的个数
def Analysis(data):
    result = []
    色泽1 = []
    根蒂2 = []
    敲声3 = []
    纹理4 = []
    脐部5 = []
    触感6 = []
    # 统计乌黑的个数
    num = 0
    for i in range(data.shape[0]):
        if data[i][1] == 0:
            num += 1
    色泽1.append(num)
    # 统计青绿的个数
    num = 0
    for i in range(data.shape[0]):
        if data[i][1] == 1:
            num += 1
    色泽1.append(num)
    # 统计浅白的个数
    num = 0
    for i in range(data.shape[0]):
        if data[i][1] == 2:
            num += 1
    色泽1.append(num)
    # 统计蜷缩的个数
    num = 0
    for i in range(data.shape[0]):
        if data[i][2] == 0:
            num += 1
    根蒂2.append(num)
    # 统计稍蜷的个数
    num = 0
    for i in range(data.shape[0]):
        if data[i][2] == 1:
            num += 1
    根蒂2.append(num)
    # 统计硬挺的个数
    num = 0
    for i in range(data.shape[0]):
        if data[i][2] == 2:
            num += 1
    根蒂2.append(num)
    # 统计沉闷的个数
    num = 0
    for i in range(data.shape[0]):
        if data[i][3] == 0:
            num += 1
    敲声3.append(num)
    # 统计浊响的个数
    num = 0
    for i in range(data.shape[0]):
        if data[i][3] == 1:
            num += 1
    敲声3.append(num)
    # 统计清脆的个数
    num = 0
    for i in range(data.shape[0]):
        if data[i][3] == 2:
            num += 1
    敲声3.append(num)
    # 统计模糊的个数
    num = 0
    for i in range(data.shape[0]):
        if data[i][4] == 0:
            num += 1
    纹理4.append(num)
    # 统计稍糊的个数
    num = 0
    for i in range(data.shape[0]):
        if data[i][4] == 1:
            num += 1
    纹理4.append(num)
    # 统计清晰的个数
    num = 0
    for i in range(data.shape[0]):
        if data[i][4] == 2:
            num += 1
    纹理4.append(num)
    # 统计凹陷的个数
    num = 0
    for i in range(data.shape[0]):
        if data[i][5] == 0:
            num += 1
    脐部5.append(num)
    # 统计稍凹的个数
    num = 0
    for i in range(data.shape[0]):
        if data[i][5] == 1:
            num += 1
    脐部5.append(num)
    # 统计平坦的个数
    num = 0
    for i in range(data.shape[0]):
        if data[i][5] == 2:
            num += 1
    脐部5.append(num)
    # 统计软粘的个数
    num = 0
    for i in range(data.shape[0]):
        if data[i][6] == 0:
            num += 1
    触感6.append(num)
    # 统计硬滑的个数
    num = 0
    for i in range(data.shape[0]):
        if data[i][6] == 1:
            num += 1
    触感6.append(num)
    # 将特征添加到result中
    result.append(色泽1)
    result.append(根蒂2)
    result.append(敲声3)
    result.append(纹理4)
    result.append(脐部5)
    result.append(触感6)
    return result


# 利用基尼指数划分决策树的第一步: 求出各属性的基尼指数并取最小的下标
def Gini1(data):
    result = []
    min = 0
    色泽1 = 1 - (data[0][0] / (data[0][0] + data[0][1] + data[0][2])) ** 2 - (
            data[0][1] / (data[0][0] + data[0][1] + data[0][2])) ** 2 - (
                  data[0][2] / (data[0][0] + data[0][1] + data[0][2])) ** 2
    根蒂2 = 1 - (data[1][0] / (data[1][0] + data[1][1] + data[1][2])) ** 2 - (
            data[1][1] / (data[1][0] + data[1][1] + data[1][2])) ** 2 - (
                  data[1][2] / (data[1][0] + data[1][1] + data[1][2])) ** 2
    敲声3 = 1 - (data[2][0] / (data[2][0] + data[2][1] + data[2][2])) ** 2 - (
            data[2][1] / (data[2][0] + data[2][1] + data[2][2])) ** 2 - (
                  data[2][2] / (data[2][0] + data[2][1] + data[2][2])) ** 2
    纹理4 = 1 - (data[3][0] / (data[3][0] + data[3][1] + data[3][2])) ** 2 - (
            data[3][1] / (data[3][0] + data[3][1] + data[3][2])) ** 2 - (
                  data[3][2] / (data[3][0] + data[3][1] + data[3][2])) ** 2
    脐部5 = 1 - (data[4][0] / (data[4][0] + data[4][1] + data[4][2])) ** 2 - (
            data[4][1] / (data[4][0] + data[4][1] + data[4][2])) ** 2 - (
                  data[4][2] / (data[4][0] + data[4][1] + data[4][2])) ** 2
    触感6 = 1 - (data[5][0] / (data[5][0] + data[5][1])) ** 2 - (data[5][1] / (data[5][0] + data[5][1])) ** 2
    result.append(色泽1)
    result.append(根蒂2)
    result.append(敲声3)
    result.append(纹理4)
    result.append(脐部5)
    result.append(触感6)
    # 取result中值最小的下标为min
    for i in range(len(result)):
        if result[i] < result[min] and result[i] != 0:
            min = i
    print(result)
    return min + 1


# 利用基尼指数划分决策树的第二步:利用下标划分数据集
def ChangeData2(data, min):
    result = []
    result1 = []
    result2 = []
    result3 = []
    if min == 6:
        for i in range(data.shape[0]):
            if data[i][6] == 0:
                result1.append(data[i])
            elif data[i][6] == 1:
                result2.append(data[i])
        result.append(result1)
        result.append(result2)
    else:
        for i in range(data.shape[0]):
            if data[i][6] == 0:
                result1.append(data[i])
            elif data[i][6] == 1:
                result2.append(data[i])
            elif data[i][6] == 2:
                result3.append(data[i])
        result.append(result1)
        result.append(result2)
        result.append(result3)
    return result


# 定义一个多叉树
class TreeNode:
    def __init__(self, value):
        self.value = value
        self.data = data
        self.children = []

    def add_child(self, node):
        self.children.append(node)


# 深度优先遍历多叉树
def dfs(node, visit=lambda node: print(node.data)):
    visit(node)
    for child in node.children:
        dfs(child, visit)


data = DataSet().values  # 读表
print(data)
data2 = ChangeData1(data)  # 转换表格数据为数字
print(data2)
data3 = Analysis(data2)  # 统计各属性的个数
print(data3)
data4 = Gini1(data3)  # 利用基尼指数划分决策树的第一步:求出各属性的基尼指数并取最小的下标
print(data4)
data5 = ChangeData2(data2, data4)  # 利用基尼指数划分决策树的第二步:利用下标划分数据集
print(data5[0])
print(data5[1])


# root = TreeNode(1)
# root.data = data2
# child1 = TreeNode(2)
# child1.data=data5[0]
# child2 = TreeNode(3)
# child2.data=data5[1]
#
# root.add_child(child1)
# root.add_child(child2)
# print("DFS Traversal:")
# dfs(root)



五、总结:

决策树易于理解和解释,但可能会因为选择的特征和树的结构导致过拟合或欠拟合。现代的决策树算法,如ID3、C4.5、CART和随机森林,都包含优化策略来提高性能和稳定性。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值