【机器学习】决策树详解

news/2024/11/28 6:52:30/

摘要: 本文深入探讨机器学习中的决策树算法。首先介绍决策树的基本概念与原理,包括信息熵、信息增益等核心概念,详细阐述决策树的构建过程,如特征选择、节点分裂与停止条件等。通过大量代码示例展示决策树在数据分类与回归任务中的应用,包括数据预处理、模型训练、模型评估与调优。同时,对决策树的优缺点进行分析,并探讨其在实际应用中的扩展与变体,如随机森林、梯度提升树等,为读者全面理解和应用决策树算法提供丰富的知识与实践指导。

一、引言

机器学习在当今数据驱动的时代扮演着极为重要的角色,而决策树是其中一种经典且广泛应用的算法。决策树以一种直观、易于理解的方式对数据进行分类和预测,其类似树形结构的决策流程能够有效地处理各种类型的数据,无论是结构化数据还是半结构化数据,都能展现出良好的性能。

二、决策树的基本原理

(一)信息熵

信息熵是决策树构建过程中的一个关键概念,用于衡量数据的不确定性或混乱程度。对于一个具有个类别的数据集,其信息熵的计算公式为:

其中Pk是数据集中属于第类别的样本比例。

以下是计算信息熵的代码示例:

import mathdef entropy(data):# 统计各类别样本数量class_count = {}for sample in data:label = sample[-1]if label in class_count:class_count[label] += 1else:class_count[label] = 1# 计算信息熵entropy_value = 0total_samples = len(data)for count in class_count.values():probability = count / total_samplesentropy_value -= probability * math.log2(probability)return entropy_value

(二)信息增益

信息增益用于衡量某个特征对数据集分类的贡献程度。

def information_gain(data, feature):# 计算数据集的信息熵base_entropy = entropy(data)# 特征取值的集合feature_values = set([sample[feature] for sample in data])new_entropy = 0# 遍历特征取值for value in feature_values:# 划分数据集subset = [sample for sample in data if sample[feature] == value]# 计算子集的信息熵并加权求和new_entropy += (len(subset) / len(data)) * entropy(subset)# 计算信息增益gain = base_entropy - new_entropyreturn gain

 

三、决策树的构建过程

(一)特征选择

在构建决策树时,首先需要从数据集中选择最佳的特征进行节点分裂。通常采用信息增益、信息增益比或基尼指数等指标来评估特征的优劣。以信息增益为例,选择信息增益最大的特征作为当前节点的分裂特征。

def choose_best_feature(data):# 特征数量num_features = len(data[0]) - 1best_gain = 0best_feature = -1# 遍历所有特征for i in range(num_features):# 计算特征的信息增益gain = information_gain(data, i)# 更新最佳特征if gain > best_gain:best_gain = gainbest_feature = ireturn best_feature

(二)节点分裂

根据选定的特征将数据集划分为多个子集,每个子集对应于该特征的一个取值。然后为每个子集创建一个子节点,并递归地对这些子节点进行处理,直到满足停止条件。

def split_data(data, feature, value):# 划分数据集subset = []for sample in data:if sample[feature] == value:# 去除已分裂的特征new_sample = sample[:feature] + sample[feature + 1:]subset.append(new_sample)return subset

(三)停止条件

决策树的构建通常在以下情况停止:

  1. 当节点中的样本都属于同一类别时,该节点成为叶节点,类别即为该节点的类别。
  2. 当没有可用于分裂的特征时,将该节点标记为叶节点,并将其中样本数量最多的类别作为该节点的类别。
  3. 当节点中的样本数量小于某个阈值时,也将其作为叶节点处理。
    def majority_class(class_list):# 统计各类别数量class_count = {}for c in class_list:if c in class_count:class_count[c] += 1else:class_count[c] = 1# 返回数量最多的类别sorted_classes = sorted(class_count.items(), key=lambda x: x[1], reverse=True)return sorted_classes[0][0]def build_tree(data, features):# 获取样本的类别列表class_list = [sample[-1] for sample in data]# 停止条件 1:所有样本属于同一类别if class_list.count(class_list[0]) == len(class_list):return class_list[0]# 停止条件 2:无特征可用if len(features) == 0:return majority_class(class_list)# 选择最佳特征best_feature = choose_best_feature(data)best_feature_name = features[best_feature]# 创建树节点tree = {best_feature_name: {}}# 去除已使用的特征remaining_features = features[:best_feature] + features[best_feature + 1:]# 获取最佳特征的取值feature_values = set([sample[best_feature] for sample in data])# 递归构建子树for value in feature_values:# 划分数据集subset = split_data(data, best_feature, value)# 构建子树tree[best_feature_name][value] = build_tree(subset, remaining_features)return tree

    四、决策树在数据分类中的应用

    (一)数据预处理

     

    首先需要对数据进行预处理,包括数据读取、数据清洗、特征工程等步骤。例如,处理缺失值、将分类特征进行编码等。

    import pandas as pd
    from sklearn.preprocessing import LabelEncoder# 读取数据
    data = pd.read_csv('data.csv')# 处理缺失值
    data.fillna(data.mean(), inaxis=0, inplace=True)# 对分类特征进行编码
    label_encoders = {}
    for column in data.columns:if data[column].dtype == 'object':le = LabelEncoder()data[column] = le.fit_transform(data[column])label_encoders[column] = le# 划分特征和标签
    X = data.iloc[:, :-1].values
    y = data.iloc[:, -1].values

    (二)模型训练

     

    使用构建好的决策树算法对数据进行训练。

    # 构建决策树
    features = list(data.columns[:-1])
    tree = build_tree(list(zip(X, y)), features)

    (三)模型评估

     

    采用准确率、召回率、F1 值等指标对决策树模型的性能进行评估。可以使用交叉验证等方法来更准确地评估模型。

    from sklearn.metrics import accuracy_score, classification_report# 预测函数
    def predict(tree, sample):# 从根节点开始遍历决策树current_node = treewhile isinstance(current_node, dict):# 获取分裂特征feature_name = list(current_node.keys())[0]# 获取特征索引feature_index = features.index(feature_name)# 根据样本特征取值选择子树value = sample[feature_index]current_node = current_node[feature_name][value]return current_node# 进行预测
    y_pred = []
    for x in X:y_pred.append(predict(tree, x))# 计算准确率
    accuracy = accuracy_score(y, y_pred)
    print("Accuracy:", accuracy)# 打印分类报告
    print(classification_report(y, y_pred))

    (四)模型调优

     

    决策树的性能可以通过调整一些参数来优化,如树的深度、节点分裂所需的最小样本数等。

    # 例如限制树的深度为 3
    def build_tree_with_depth(data, features, max_depth):#... 与 build_tree 类似,但增加深度限制# 在递归构建子树时,传递当前深度并检查是否超过最大深度# 构建受限深度的决策树并评估
    tree_depth_3 = build_tree_with_depth(list(zip(X, y)), features, 3)
    y_pred_depth_3 = []
    for x in X:y_pred_depth_3.append(predict(tree_depth_3, x))
    accuracy_depth_3 = accuracy_score(y, y_pred_depth_3)
    print("Accuracy with depth 3:", accuracy_depth_3)


http://www.ppmy.cn/news/1550554.html

相关文章

SpringMVC前后端数据交互

一、JSON格式数据 1、定义 JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式,已被广泛用于数据保存和交换,是迄今为止最为理想的数据交换语言。 JSON 独立于编程语言 层次结构简洁和清晰 易于人阅读和编写,也易于…

Vue框架开发一个简单的购物车(Vue.js)

让我们利用所学知识来开发一个简单的购物车 &#xff08;记得暴露属性和方法&#xff01;&#xff01;&#xff01;&#xff09; 首先来看一下最基本的一个html框架 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"&…

Rust语言俄罗斯方块(漂亮的界面案例+详细的代码解说+完美运行)

tetris-demo A Tetris example written in Rust using Piston in under 500 lines of code 项目地址: https://gitcode.com/gh_mirrors/te/tetris-demo 项目介绍 "Tetris Example in Rust, v2" 是一个用Rust语言编写的俄罗斯方块游戏示例。这个项目不仅是一个简单…

RabbitMQ 安装延迟队列插件 rabbitmq_delayed_message_exchange

前言&#xff1a; RabbitMQ 延迟队列插件&#xff08;rabbitmq_delayed_message_exchange&#xff09;是一个社区开发的插件&#xff0c;它为 RabbitMQ 添加了支持延迟消息的功能。通过这个插件&#xff0c;用户可以创建一种特殊的交换机类型 x-delayed-message&#xff0c;该…

【React】React 组件通信:多种方式与最佳实践

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 React 组件通信&#xff1a;多种方式与最佳实践组件通信的基本概念父子组件通信…

责任链模式在spring security过滤器链中的应用

责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为型设计模式&#xff0c;它允许多个对象按照顺序处理请求&#xff0c;并且每个对象可以选择自己是否处理该请求或将其传递给下一个对象。 在Spring Security中&#xff0c;责任链模式得到了广泛应…

C++多线程——线程

1、线程与进程 进程是一个具有独立功能程序的运行实体&#xff0c;如某一个程序&#xff0c;运行时便产生一个进程&#xff1b;通常一个进程包含一个或多个线程。普通C程序多是只含有一个线程的进程&#xff0c;但是大多数情况下遇到的是多线程的进程。 线程与进程都是操作系统…

IDEA自定义帆软函数步骤详解

前序: 在帆软里面有很多内置函数可以供我们使用,比如计算总和的SUM()函数, 计算绝对值的ABS()函数等等,但是很多时候随着业务的复杂性,这些函数已经不满足于我们复杂的计算要求,所以我们可以自定义一些函数来满足我们的需求。 自定义函数列表 (一)如何新增自定义函数 …