机器学习笔记(四)

本文介绍了决策树在机器学习中的关键应用,包括其构造原理、特征选择方法(信息增益、增益率和基尼指数)、过拟合问题及其剪枝策略。通过实例演示了决策树的构建过程,以及如何通过sklearn处理实际数据集,如Wine数据集,展示决策树的实用性。
摘要由CSDN通过智能技术生成

        决策树是一种在机器学习中广泛应用的模型,用于分类和回归任务。它采用树状结构,由节点(表示数据集中的特征)、边(表示特征上的取值)和叶子节点(表示输出标签)组成。构建决策树的过程涉及选择特征、划分数据、递归构建子树和定义停止条件。决策树的优势在于其易于理解和解释的特点,以及能够自动处理特征选择的能力。通过在节点上进行适当的分割,决策树能够高效地对数据进行分类或回归,提供清晰的决策路径。然而,需要注意的是决策树容易过拟合,通常需要采用剪枝等技术来改善性能。总体而言,决策树是一个强大而灵活的工具,可用于各种机器学习应用中。

决策树的基本流程:

决策过程中提出的每个判定问题都是对某个属性的“测试”

每个测试的结果或是导出最终结论,或者导出进一步的判定问题,其考虑范围是在上次决策结果的限定范围之内

从根结点到每个叶结点的路径对应了一个判定测试序列

决策树学习的目的是为了产生一棵泛化能力强即处理未见示例能力强的决策树

(PS:泛化能力强是指机器学习模型在面对新、未见过的数据时表现良好的能力。换句话说,一个具有强泛化能力的模型能够从训练数据中学到通用的模式和规律,而不是仅仅记住训练数据的具体情况。在机器学习中,过度拟合(overfitting)是一个常见的问题,即模型在训练数据上表现很好,但在新数据上表现差。强泛化能力有助于防止过度拟合,使模型更具有实用性和推广能力。)

        如上图所示,决策树的基本流程类似于一个找对象的模型,会从年龄、长相、收入情况、是否公务员等等属性一次决断。

        与此同时,问题也随之展开。如果一个属性只出现两种情况,则推理完整个决策树则需要进行一个满二叉树的构建,假设满二叉树的高度为h,则节点数量为 2^(h+1) - 1,可选参数多一些的话,计算量是非常爆炸的。决策树可以通过一定的方式削减分支的个数,减少计算数量负担的同时也加快推理的速度。

在进行决策树构建的时候,我们可能遇到如下问题:

        由上图的树类结构可以看出对于“白不白”这个属性划分情况下再接着对“富不富、“美不美”两个属性进行划分,观察到,对于“富不富”这一属性的“富”决策选项的最终结果都会对应“去”这一结论。由此可以得出,如果采取较为合理的决策顺序,能大大加快决策效率。

        以及,对于左边分支的“美不美”选项,两种选择得出的结论出现了相同的情况。也就是说,在当前情况下“美不美”的判断对于次决策树的流程是可有可无的,如果替换为下图的流程,能一定程度上提高决策树的效率。

(1)当前结点包含的样本全部属于同一类别

        无需划分,叶子节点标记为类别

(2)当前属性集为空,或所有样本在所有属性上取值相同:

        当前结点标记为叶子节点,类别=该结点所含样本最多的类别

(3)当前结点包含的样本集合为空:

        当前结点标记为叶子节点,类别=该结点的父节点所含样本最多的类别

决策树的划分选择:

决策树学习的关键在于如何选择最优划分属性,而最优的划分能够使得决策树的分支结点尽可能包含同一类别的样本,从而提高模型的泛化能力。这个过程中,我们追求结点的“纯度”(purity)逐渐增加。

在经典的属性划分方法中,有几种常用的标准:

  1. 信息增益(ID3): 该方法基于信息论中的熵概念,通过计算划分前后的信息熵差值,选择信息增益最大的属性作为划分依据。信息增益越大,表示选择该属性能够带来更大的纯度提升。

  2. 增益率(C4.5): 这个方法是为了解决信息增益对取值较多的属性有偏好的问题。增益率考虑了属性的取值数目,通过对信息增益进行归一化,选择增益率最大的属性进行划分。

  3. 基尼指数(CART): 基尼指数是衡量数据集纯度的一种方法,表示随机抽取两个样本,其类别标签不一致的概率。基尼指数越低,表示结点的纯度越高。CART(Classification and Regression Trees)算法通过选择基尼指数最小的属性进行划分,以达到提高纯度的目的。

信息熵的定义为:

Ent(D)的值越小,则D的纯度越高

计算信息熵时约定:若p = 0,则plog2p=0

Ent(D)的最小值为0,最大值为log2|y|

        离散属性a有V个可能的取值{a1, a2, ..., aV},用a来进行划分,则会产生V个分支结点,其中第v个分支结点包含了D中所有在属性a上取值为av的样本,记为Dv。则可计算出用属性a对样本集D进行划分所获得的“信息增益”:

                  

为分支结点权重,样本数越多的分支结点的影响越大

简单案例:

import pandas as pd
import math

# 创建一个简单的数据集
data = {
    'Outlook': ['Sunny', 'Sunny', 'Overcast', 'Rainy', 'Rainy', 'Rainy', 'Overcast', 'Sunny', 'Sunny', 'Rainy'],
    'Temperature': ['Hot', 'Hot', 'Hot', 'Mild', 'Cool', 'Cool', 'Cool', 'Mild', 'Cool', 'Mild'],
    'PlayTennis': ['No', 'No', 'Yes', 'Yes', 'Yes', 'No', 'Yes', 'No', 'Yes', 'Yes']
}

df = pd.DataFrame(data)

def calculate_entropy(target_column):
    entropy = 0
    values = target_column.unique()
    for value in values:
        prob = len(target_column[target_column == value]) / len(target_column)
        entropy -= prob * math.log2(prob)
    return entropy

def calculate_information_gain(data, feature, target):
    # 计算总体的信息熵
    total_entropy = calculate_entropy(data[target])

    # 计算特征的加权信息熵
    unique_values = data[feature].unique()
    weighted_entropy = 0
    for value in unique_values:
        subset = data[data[feature] == value]
        prob = len(subset) / len(data)
        weighted_entropy += prob * calculate_entropy(subset[target])

    # 计算信息增益
    information_gain = total_entropy - weighted_entropy
    return information_gain

# 使用Outlook特征计算信息增益
info_gain_outlook = calculate_information_gain(df, 'Outlook', 'PlayTennis')
print("Information Gain for Outlook:", info_gain_outlook)

# 使用Temperature特征计算信息增益
info_gain_temperature = calculate_information_gain(df, 'Temperature', 'PlayTennis')
print("Information Gain for Temperature:", info_gain_temperature)

  
      这时候就出现了一个小小的尝试,某小A一次不小心把编号也当做属性传入,结果每个编号对应的结论都是固定的,效果异常的好呀,由此引出了信息增益对可取值数目较多的属性有所偏好这一问题。

为了缓和这种现象,引入增益率的计算方法:

可定义增益率:

其中:                

        称为属性a的“固有值” [Quinlan, 1993] ,属性a的可能取值数目越多(即V越大),则IV(a)的值通常就越大

虽然这种方法解决了对数目较多的属性有所偏好的问题,但同样会产生反作用

简单案例:

import pandas as pd
from math import log2

# 创建简单的数据集
data = {
    'Outlook': ['Sunny', 'Sunny', 'Overcast', 'Rainy', 'Rainy', 'Rainy', 'Overcast', 'Sunny', 'Sunny', 'Rainy'],
    'PlayTennis': ['No', 'No', 'Yes', 'Yes', 'Yes', 'No', 'Yes', 'No', 'Yes', 'Yes']
}

df = pd.DataFrame(data)

def calculate_entropy(column):
    # 计算给定列的信息熵
    entropy = 0
    values = column.value_counts() / len(column)
    for value in values:
        entropy -= value * log2(value)
    return entropy

def calculate_information_gain(data, feature, target):
    # 计算信息增益
    total_entropy = calculate_entropy(data[target])
    feature_values = data[feature].unique()

    weighted_entropy = 0
    for value in feature_values:
        subset = data[data[feature] == value]
        weighted_entropy += len(subset) / len(data) * calculate_entropy(subset[target])

    information_gain = total_entropy - weighted_entropy
    return information_gain

def calculate_gain_ratio(data, feature, target):
    # 计算增益率
    information_gain = calculate_information_gain(data, feature, target)
    intrinsic_value = -sum((len(data[data[feature] == value]) / len(data)) * log2(len(data[data[feature] == value]) / len(data)) for value in data[feature].unique())
    
    gain_ratio = information_gain / intrinsic_value if intrinsic_value != 0 else 0
    return gain_ratio

# 计算Outlook特征的增益率
gain_ratio_outlook = calculate_gain_ratio(df, 'Outlook', 'PlayTennis')
print("Gain Ratio for Outlook:", gain_ratio_outlook)

        可以看到,信息增益及增益率里都存在大量的取对数步骤,众所周知,取对数这一步骤在计算机计算里面是一个很贵的过程,我们迫切需要一个简单,好算,又能衡量决策树划分标准的算法。由此引出:基尼指数。

定义:分类问题中,假设D有K个类,样本点属于第k类的概率为p_k,则概率分布的基尼值定义为:

                ​​​​​​​        

反映了随机抽取两个样本,其类别标记不一致的概率

简单案例:
import pandas as pd

# 创建简单的数据集
data = {
    'Outlook': ['Sunny', 'Sunny', 'Overcast', 'Rainy', 'Rainy', 'Rainy', 'Overcast', 'Sunny', 'Sunny', 'Rainy'],
    'PlayTennis': ['No', 'No', 'Yes', 'Yes', 'Yes', 'No', 'Yes', 'No', 'Yes', 'Yes']
}

df = pd.DataFrame(data)

def calculate_gini(column):
    # 计算给定列的基尼指数
    values = column.value_counts() / len(column)
    gini = 1 - sum(value**2 for value in values)
    return gini

def calculate_gini_index(data, feature, target):
    # 计算基尼指数
    total_gini = calculate_gini(data[target])
    feature_values = data[feature].unique()

    weighted_gini = 0
    for value in feature_values:
        subset = data[data[feature] == value]
        weighted_gini += len(subset) / len(data) * calculate_gini(subset[target])

    gini_index = weighted_gini
    return gini_index

# 计算Outlook特征的基尼指数
gini_index_outlook = calculate_gini_index(df, 'Outlook', 'PlayTennis')
print("Gini Index for Outlook:", gini_index_outlook)

剪枝处理:
 

为什么要剪枝处理?

决策树剪枝是为了防止过拟合(overfitting)的问题,提高模型的泛化能力。过拟合是指模型在训练数据上表现得很好,但在未见过的新数据上表现较差的情况。

决策树容易过拟合的原因在于:

  1. 过多分支: 决策树在训练时会尽量将训练数据中的每个细节都考虑进去,导致树的深度较大,分支过多,从而过度适应了训练数据的噪声和特殊情况。

  2. 纯度提高不均匀: 在划分数据时,某些分支可能只包含极少的样本,导致这些分支的纯度提高不具有泛化性。

判断决策树泛化性能是否提升的方法 留出法:预留一部分数据用作“验证集”以进行性能评估

 剪枝的基本策略:

  1. 预剪枝(Pre-pruning): 在树的构建过程中,在每次划分前判断是否进行划分,判断的依据可以是限制树的最大深度、限制每个叶子节点的最小样本数等。预剪枝通过提前停止树的生长,防止过度拟合。

  2. 后剪枝(Post-pruning): 在树的构建完成后,通过自下而上的方式,对树进行剪枝。具体做法是逐步将叶子节点替换为其父节点,然后评估剪枝前后模型的性能,如果剪枝后性能提高或保持不变,则进行剪枝操作。

 一、预剪枝

通过提前停止树的构建而对树剪枝,主要方法有:  

1.当决策树达到预设的高度时就停止决策树的生长  

2.达到某个节点的实例集具有相同的特征向量(属性取值相同),即使这些实例不属于同一类,也可以停止决策树的生长。  

3.定义一个阈值,当达到某个节点的实例个数小于阈值时就可以停止决策树的生长。  

4.通过计算每次扩张对系统性能的增益,决定是否停止决策树的生长。 上述不足:阈值属于超参数,很难找到过拟合--欠拟合的trade-off。

        决策树生成过程中,对每个结点在划分前先进行估计,若当前结点的划分不能带来决策树泛化性能提升,则停止划分并将当前结点记为叶结点,其类别标记为该节点对应训练样例数最多的类别。

二、后剪枝

先从训练集生成一棵完整的决策树,然后自底向上地对非叶结点进行分析计算,若将该结点对应的子树替换为叶结点能带来决策树泛化性能提升,则将该子树替换为叶结点。

决策树剪枝是为了避免过拟合,提高模型的泛化能力。预剪枝是在树的构建过程中就进行剪枝,通过设定条件(如最大深度、最小样本数)提前停止树的生长,具有计算开销小和实现简单的优点。然而,过早停止树的生长可能导致模型过于简单,存在欠拟合的风险。另一方面,后剪枝是在构建完整树后通过自下而上的方式对树进行剪枝,能够更灵活地选择剪枝节点,适应不同的数据集。尽管后剪枝在减小过拟合风险方面表现较好,但由于需要在完整树的基础上进行计算,其计算开销相对较大。在实际应用中,选择预剪枝还是后剪枝需根据具体问题和数据特点进行权衡,以达到更好的模型泛化性能。

决策树应用案例

这段代码使用sklearn中的决策树分类器处理wine数据集。首先,通过load_wine加载数据集,然后划分为训练集和测试集。接着,构建了一个决策树模型,并通过设置不同参数进行训练。代码还探索了决策树模型的属性和方法,包括标签种类、特征重要性权重、决策树深度等。最后,使用训练好的模型对测试集进行预测,计算了模型在测试集上的准确率,并通过graphviz库将决策树可视化为PDF文件。这段代码全面展示了决策树模型的构建、探索和可视化过程。

from sklearn import tree
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
import pandas as pd
import graphviz

# 加载wine数据集
wine_data = load_wine()
wine_features = pd.DataFrame(wine_data.data, columns=wine_data.feature_names)
wine_label = pd.DataFrame(wine_data.target, columns=['target'])

Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine_features, wine_label, test_size=0.3)

clf = tree.DecisionTreeClassifier(criterion="entropy",
                                  splitter="best",
                                  max_depth=5,
                                  min_samples_split=0.15,
                                  min_samples_leaf=0.05,
                                  random_state=1,
                                  class_weight="balanced")

clf = clf.fit(Xtrain, Ytrain)

classes = clf.classes_
feature_importance = clf.feature_importances_
max_features = clf.max_features_
n_classes = clf.n_classes_
n_features_in = clf.n_features_in_
n_outputs = clf.n_outputs_
tree_structure = clf.tree_

clf.apply(Xtest)
clf.cost_complexity_pruning_path(Xtest, Ytest)
clf.decision_path(Xtest)
tree_depth = clf.get_depth()
n_leaves = clf.get_n_leaves()
params = clf.get_params()
predictions = clf.predict(Xtest)
log_probabilities = clf.predict_log_proba(Xtest)
probabilities = clf.predict_proba(Xtest)
accuracy = clf.score(Xtest, Ytest)

dot_data = tree.export_graphviz(clf,
                                out_file=None,
                                feature_names=wine_features.columns,
                                class_names=[str(target) for target in wine_data.target_names],
                                filled=True, rounded=True, special_characters=True)
graph = graphviz.Source(dot_data)
graph.render("wine_decision_tree")

效果如图:

总结:

        学习决策树的过程中,我深刻理解了它在机器学习中的关键角色。决策树以直观的树状结构为特征,由节点、边和叶子节点组成,用于解决分类和回归问题。其构建过程包括选择特征、划分数据、递归构建子树和定义停止条件等步骤。决策树以其易解释性和自动处理特征选择的能力而著称,但也容易过拟合,需要剪枝等技术来改善性能。在学习的过程中,了解了决策树的基本流程,类似于一个找对象的模型,通过一系列属性的判断逐步缩小范围。属性划分方法中的信息增益、增益率和基尼指数等标准在选择最优划分属性时发挥关键作用,通过衡量结点纯度的提升指导决策树的构建。最后,通过一个决策树应用案例,全面展示了决策树模型的构建过程,为理解这一机器学习工具提供了深入的见解。总体而言,学习决策树为我提供了对机器学习中这一强大而灵活的模型的全面认识。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NINGCONG2021

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值