【机器学习】ID3、C4.5、CART 算法

目录

常见的决策树算法

1. ID3

2. C4.5

3. CART

决策树的优缺点

优点:

缺点:

决策树的优化

常见的决策树算法

1. ID3

ID3(Iterative Dichotomiser 3)算法使用信息增益作为特征选择的标准。它是一种贪心算法,信息增益表示按某特征划分数据集前后信息熵的变化量,变化量越大,表示使用该特征划分的效果越好。但ID3偏向于选择取值较多的特征,可能导致过拟合。

以下是ID3算法的实现步骤:

1. 计算数据集的熵:熵是度量数据集无序程度的指标。
2. 计算每个属性的信息增益:信息增益是数据集的熵减去按照该属性分割后的条件熵。
3. 选择信息增益最大的属性:作为决策节点。
4. 分割数据集:根据选定的属性和它的值,将数据集分割成若干子集。
5. 递归构建决策树:对每个子集重复步骤1-4,直到所有数据都属于同一类别,或者已达到预设的最大深度。

以下是使用Python实现ID3算法的一个简单示例:

import numpy as np
import pandas as pd

# 计算熵
def calc_entropy(target_col):
    entropy = -np.sum([len(target_col[target_col == val]) / len(target_col) * np.log2(len(target_col[target_col == val]) / len(target_col))
                       for val in np.unique(target_col)])
    return entropy

# 按照给定属性分裂数据集
def split_dataset(dataset, index, value):
    return dataset[dataset.iloc[:, index] == value]

# 选择最好的数据集属性
def choose_best_feature_to_split(dataset):
    num_features = dataset.shape[1] - 1
    base_entropy = calc_entropy(dataset.iloc[:, -1])
    best_info_gain = 0.0
    best_feature = -1
    for i in range(num_features):
        feat_list = dataset.iloc[:, i]
        unique_vals = set(feat_list)
        new_entropy = 0.0
        for value in unique_vals:
            sub_dataset = split_dataset(dataset, i, value)
            prob = len(sub_dataset) / len(dataset)
            new_entropy += prob * calc_entropy(sub_dataset.iloc[:, -1])
        info_gain = base_entropy - new_entropy
        if info_gain > best_info_gain:
            best_info_gain = info_gain
            best_feature = i
    return best_feature

# 构建决策树
def create_tree(dataset, labels):
    # 检查数据集是否为空
    if len(dataset) == 0:
        return None
    # 检查数据集中的所有目标变量是否相同
    if len(set(dataset.iloc[:, -1])) <= 1:
        return dataset.iloc[0, -1]
    # 检查是否已达到最大深度或者没有更多的特征
    if len(dataset.columns) == 1 or len(set(dataset.iloc[:, -1])) == 1:
        return majority_cnt(dataset.iloc[:, -1])
    # 选择最好的数据集属性
    best_feat = choose_best_feature_to_split(dataset)
    best_feat_label = dataset.columns[best_feat]
    my_tree = {best_feat_label: {}}
    del(dataset[:, best_feat])
    unique_vals = set(dataset.iloc[:, -1])
    for value in unique_vals:
        sub_labels = best_feat_label + "_" + str(value)
        my_tree[best_feat_label][value] = create_tree(split_dataset(dataset, best_feat, value), sub_labels)
    return my_tree

# 找到出现次数最多的目标变量值
def majority_cnt(class_list):
    class_count = {}
    for vote in class_list:
        if vote not in class_count.keys():
            class_count[vote] = 1
        else:
            class_count[vote] += 1
    sorted_class_count = sorted(class_count.items(), key=lambda item: item[1], reverse=True)
    return sorted_class_count[0][0]

# 加载数据集
dataset = pd.read_csv("your_dataset.csv")  # 替换为你的数据集路径
labels = dataset.iloc[:, -1].name
dataset = dataset.iloc[:, 0:-1]  # 特征数据

# 创建决策树
my_tree = create_tree(dataset, labels)
print(my_tree)

:这个实现是为了教学目的而简化的,实际应用中通常会使用更高级的库和算法,如 scikit-learn 中的 DecisionTreeClassifier。


2. C4.5

C4.5是ID3的改进版,使用信息增益比替代信息增益作为特征选择标准,从而克服了ID3倾向于选择多值特征的缺点。此外,C4.5还能处理连续型特征和缺失值

实现C4.5算法可以通过多种编程语言,但这里我将提供一个简化的Python实现,使用Python的基本库来构建决策树。这个实现将包括计算信息熵、信息增益、信息增益比,并基于这些度量来构建决策树。

1. 计算信息熵

信息熵是度量数据集无序程度的指标,计算公式为:

其中 pi  是第 i  个类别的样本在数据集中的比例。

2. 计算信息增益

信息增益是度量在知道特征  A  的条件下,数据集  S  的熵减少的程度。计算公式为:

其中 Sv  是特征  A  值为  v  时的子集。

3. 计算信息增益比

信息增益比是信息增益与特征  A  的固有信息的比值,计算公式为:

其中,分裂信息 Split Information(S, A)  是度量特征  A  的值分布的熵:

4. 构建决策树

使用以上计算方法,我们可以构建一个简单的C4.5决策树:

import numpy as np
import pandas as pd

def entropy(target_col):
    elements, counts = np.unique(target_col, return_counts=True)
    probabilities = counts / counts.sum()
    return -np.sum(probabilities * np.log2(probabilities))

def information_gain(data, feature, target):
    total_entropy = entropy(data[target])
    values = data[feature].unique()
    weighted_entropy = 0.0
    for value in values:
        sub_data = data[data[feature] == value]
        weighted_entropy += (len(sub_data) / len(data)) * entropy(sub_data[target])
    return total_entropy - weighted_entropy

def gain_ratio(data, feature, target):
    ig = information_gain(data, feature, target)
    split_info = entropy(data[feature])
    return ig / split_info if split_info != 0 else 0

def choose_best_feature_to_split(data, features, target):
    best_feature = None
    max_gain_ratio = -1
    for feature in features:
        gain_ratio_value = gain_ratio(data, feature, target)
        if gain_ratio_value > max_gain_ratio:
            max_gain_ratio = gain_ratio_value
            best_feature = feature
    return best_feature

def c45(data, features, target, tree=None, depth=0):
    if len(data[target].unique()) == 1:
        return data[target].mode()[0]
    
    if depth == 0:
        depth = 0
    elif depth > 10:  # Limit the depth to avoid overfitting
        return data[target].mode()[0]
    
    best_feat = choose_best_feature_to_split(data, features, target)
    if best_feat is None:
        return data[target].mode()[0]
    
    if len(data[best_feat].unique()) == 1:
        return data[target].mode()[0]
    
    tree = tree if tree else {best_feat: {}}
    unique_vals = data[best_feat].unique()
    
    for value in unique_vals:
        subtree = c45(data[data[best_feat] == value], features, target, tree=tree, depth=depth+1)
        tree[best_feat][value] = subtree
    return tree

# Example usage
data = pd.DataFrame({
    'Outlook': ['Sunny', 'Sunny', 'Overcast', 'Rain', 'Rain', 'Rain', 'Overcast', 'Sunny', 'Sunny', 'Rain', 'Sunny', 'Overcast', 'Overcast', 'Rain'],
    'Temperature': ['Hot', 'Hot', 'Hot', 'Mild', 'Cool', 'Cool', 'Cool', 'Mild', 'Cool', 'Mild', 'Mild', 'Mild', 'Hot', 'Mild'],
    'Humidity': ['High', 'High', 'High', 'High', 'Normal', 'Normal', 'Normal', 'High', 'Normal', 'Normal', 'Normal', 'High', 'Normal', 'High'],
    'Wind': ['Weak', 'Strong', 'Weak', 'Weak', 'Weak', 'Strong', 'Strong', 'Weak', 'Weak', 'Weak', 'Strong', 'Strong', 'Weak', 'Strong'],
    'PlayTennis': ['No', 'No', 'Yes', 'Yes', 'Yes', 'No', 'Yes', 'No', 'Yes', 'Yes', 'Yes', 'Yes', 'Yes', 'No']
})

features = ['Outlook', 'Temperature', 'Humidity', 'Wind']
target = 'PlayTennis'

tree = c45(data, features, target)
print(tree)

注:这个实现是一个简化版,没有包括剪枝和处理连续变量的步骤。在实际应用中,你可能需要使用更复杂的数据结构和算法来优化性能和处理更复杂的情况。


3. CART

CART(分类与回归树)是一种既能用于分类也能用于回归的决策树算法。对于分类问题,CART使用基尼不纯度作为特征选择标准;对于回归问题,则使用方差作为分裂标准。CART构建的是二叉树,每个内部节点都是二元分裂。

以下是CART算法的基本步骤:

1. 选择最佳分割特征和分割点:使用基尼不纯度(Gini impurity)或均方误差(Mean Squared Error, MSE)作为分割标准,选择能够最大程度降低不纯度的特征和分割点。

2. 分割数据集:根据选定的特征和分割点,将数据集分割成两个子集。

3. 递归构建:对每个子集重复步骤1和2,直到满足停止条件(如达到最大深度、节点中的样本数量低于阈值或无法进一步降低不纯度)。

4. 剪枝:通过剪掉树的某些部分来简化树,以防止过拟合。

以下是一个简化的Python实现CART算法,使用基尼不纯度作为分割标准:

import numpy as np
import pandas as pd

def gini_impurity(y):
    class_probabilities = y.mean(axis=0)
    return 1 - np.sum(class_probabilities ** 2)

def best_split(data, target_column, features):
    best_feature = None
    best_threshold = None
    best_gini = float('inf')
    
    for feature in features:
        for idx in np.unique(data[feature]):
            threshold = (data[feature] < idx).mean()
            split_data = data[data[feature] < idx]
            gini = (len(data) - len(split_data)) / len(data) * gini_impurity(split_data[target_column]) + \
                   len(split_data) / len(data) * gini_impurity(data[(data[target_column] == target_column.mode())[data[target_column] >= idx]][target_column])
            if gini < best_gini:
                best_gini = gini
                best_feature = feature
                best_threshold = threshold
    
    return best_feature, best_threshold

def build_tree(data, target_column, features, depth=0, max_depth=None):
    if max_depth is None:
        max_depth = np.inf
    if len(data[target_column].unique()) == 1 or len(data) == 1 or depth >= max_depth:
        return data[target_column].mode()[0]
    
    best_feature, best_threshold = best_split(data, target_column, features)
    tree = {best_feature: {}}
    features = [f for f in features if f != best_feature]
    
    split_function = lambda x: x[best_feature] < best_threshold
    left_indices = np.array([bool(split_function(row)) for row in data.itertuples()])
    right_indices = np.array([not bool(split_function(row)) for row in data.itertuples()])
    
    left_data = data[left_indices]
    right_data = data[right_indices]
    
    if not left_data.empty:
        tree[best_feature][0] = build_tree(left_data, target_column, features, depth+1, max_depth)
    if not right_data.empty:
        tree[best_feature][1] = build_tree(right_data, target_column, features, depth+1, max_depth)
    
    return tree

# Example usage
data = pd.DataFrame({
    'Feature1': [1, 2, 4, 6, 8, 10],
    'Feature2': [2, 4, 6, 8, 10, 12],
    'Target': ['Yes', 'No', 'Yes', 'No', 'Yes', 'No']
})

features = ['Feature1', 'Feature2']
target_column = 'Target'

tree = build_tree(data, target_column, features)
print(tree)

注:这个实现是一个简化的版本,没有包括剪枝步骤。在实际应用中,你可能需要使用更复杂的数据结构和算法来优化性能和处理更复杂的情况。此外,对于回归问题,需要使用均方误差(MSE)而不是基尼不纯度作为分割标准。

在实践中,通常会使用像scikit-learn这样的机器学习库来构建CART树,因为它们提供了更高效和更可靠的实现。例如,scikit-learn中的DecisionTreeClassifier和DecisionTreeRegressor类实现了CART算法。


决策树的优缺点

优点:

- 易于理解和解释。
- 可以处理数值和类别数据。
- 不需要数据标准化。
- 可以可视化。

缺点:

- 容易过拟合。
- 对于某些数据集,构建的树可能非常大。
- 对于缺失数据敏感。

决策树的优化

- 剪枝:通过减少树的大小来减少过拟合。
- 集成方法:如随机森林和梯度提升树,可以提高模型的泛化能力。


执笔至此,感触彼多,全文将至,落笔为终,感谢各位读者的支持,如果对你有所帮助,还请一键三连支持我,我会持续更新创作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/885613.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python 课程20-Scikit-learn

前言 Scikit-learn 是 Python 中最流行的机器学习库之一&#xff0c;它提供了多种用于监督学习和无监督学习的算法。Scikit-learn 的特点是简单易用、模块化且具有高效的性能。无论是初学者还是专业开发者&#xff0c;都可以借助它进行快速原型设计和模型开发。 在本教程中&a…

PFC和LLC的本质和为什么要用PFC和LLC电路原因

我们可以用电感和电容的特性,以及电压和电流之间的不同步原理来解释PFC(功率因数校正)和LLC(谐振变换器)。 电感和电容的基本概念 电感(Inductor): 电感是一种储存电能的组件。它的电流变化比较慢,电流在电感中延迟,而电压变化得比较快。可以把电感想象成一个“滞后…

Tensorflow 2.0 cnn训练cifar10 准确率只有0.1 [已解决]

cifar10 准确率只有0.1 问题描述踩坑解决办法 问题描述 如果你看的是北京大学曹健老师的tensorflow2.0,你在class5的部分可能会遇见这个问题 import matplotlib.pyplot as plt import tensorflow as tf from tensorflow.keras.layers import Dense, Dropout,MaxPooling2D,Fla…

【Verilog学习日常】—牛客网刷题—Verilog企业真题—VL69

脉冲同步器&#xff08;快到慢&#xff09; 描述 sig_a 是 clka&#xff08;300M&#xff09;时钟域的一个单时钟脉冲信号&#xff08;高电平持续一个时钟clka周期&#xff09;&#xff0c;请设计脉冲同步电路&#xff0c;将sig_a信号同步到时钟域 clkb&#xff08;100M&…

长文本溢出,中间位置显示省略号

1.说明 Flutter支持在文本末尾显示溢出省略号。现在想要实现在文本中间位置显示省略号&#xff0c;这里使用的方法是通过TextPainter计算文本宽度。&#xff08;我目前没有找到更好的方法&#xff0c;欢迎大家指教。&#xff09; 2.效果 源码 1.MiddleEllipsisTextPainter …

全球IP归属地查询-IP地址查询-IP城市查询-IP地址归属地-IP地址解析-IP位置查询-IP地址查询API接口

IP地址城市版查询接口 API是指能够根据IP地址查询其所在城市等地理位置信息的API接口。这类接口在网络安全、数据分析、广告投放等多个领域有广泛应用。以下是一些可用的IP地址城市版查询接口API及其简要介绍 1. 快证 IP归属地查询API 特点&#xff1a;支持IPv4 提供高精版、…

TypeScript 算法手册 【数组基础知识】

文章目录 1. 数组简介1.1 数组定义1.2 数组特点 2. 数组的基本操作2.1 访问元素2.2 添加元素2.3 删除元素2.4 修改元素2.5 查找元素 3. 数组的常见方法3.1 数组的创建3.2 数组的遍历3.3 数组的映射3.4 数组的过滤3.5 数组的归约3.6 数组的查找3.7 数组的排序3.8 数组的反转3.9 …

深度学习常见术语介绍

文章目录 数据集&#xff08;Dataset&#xff09;特征&#xff08;Feature&#xff09;标签&#xff08;Label&#xff09;训练集&#xff08;Training Set&#xff09;测试集&#xff08;Test Set&#xff09;验证集&#xff08;Validation Set&#xff09;模型&#xff08;Mo…

什么是文件完整性监控(FIM)

组织经常使用基于文件的系统来组织、存储和管理信息。文件完整性监控&#xff08;FIM&#xff09;是一种用于监控和验证文件和系统完整性的技术&#xff0c;识别用户并提醒用户对文件、文件夹和配置进行未经授权或意外的变更是 FIM 的主要目标&#xff0c;有助于保护关键数据和…

【NVIDIA】如何使用nvidia-smi命令管理和监控GPU

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

Golang | Leetcode Golang题解之第436题寻找右区间

题目&#xff1a; 题解&#xff1a; func findRightInterval(intervals [][]int) []int {n : len(intervals)type pair struct{ x, i int }starts : make([]pair, n)ends : make([]pair, n)for i, p : range intervals {starts[i] pair{p[0], i}ends[i] pair{p[1], i}}sort.…

面向人工智能: 对红酒数据集进行分析 (实验四)

由于直接提供截图是不切实际的&#xff0c;我将详细解释如何使用scikit-learn&#xff08;通常称为sk-learn&#xff09;自带的红酒数据集进行葡萄酒数据的分析与处理。这包括实验要求的分析、数据的初步分析&#xff08;完整性和重复性&#xff09;以及特征之间的关联关系分析…

MATLAB绘图基础9:多变量图形绘制

参考书&#xff1a;《 M A T L A B {\rm MATLAB} MATLAB与学术图表绘制》(关东升)。 9.多变量图形绘制 9.1 气泡图 气泡图用于展示三个或更多变量变量之间的关系&#xff0c;气泡图的组成要素&#xff1a; 横轴( X {\rm X} X轴)&#xff1a;表示数据集中的一个变量&#xff0c…

双端搭建个人博客

1. 准备工作 确保你的两个虚拟机都安装了以下软件: 虚拟机1(Web服务器): Apache2, PHP虚拟机2(数据库服务器): MariaDB2. 安装步骤 虚拟机1(Web服务器) 安装Apache2和PHP 更新系统包列表: sudo apt update安装Apache2: sudo apt install apache2 -y安装PHP及其Apac…

只写CURD后台管理的Java后端要如何提升自己

你是否工作3~5年后&#xff0c;发现日常只做了CURD的简单代码。 你是否每次面试就会头疼&#xff0c;自己写的代码&#xff0c;除了日常CURD简历上毫无亮点可写 抱怨过苦恼过也后悔过&#xff0c;但是站在现在的时间点回想以前&#xff0c;发现有很多事情我们是可以做的更好的。…

Spring之生成Bean

Bean的生命周期&#xff1a;实例化->属性填充->初始化->销毁 核心入口方法&#xff1a;finishBeanFactoryInitialization-->preInstantiateSingletons DefaultListableBeanFactory#preInstantiateSingletons用于实例化非懒加载的bean。 1.preInstantiateSinglet…

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-09-26

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-09-26 1. LLMs Still Can’t Plan; Can LRMs? A Preliminary Evaluation of OpenAI’s o1 on PlanBench Authors: Karthik Valmeekam, Kaya Stechly, Subbarao Kambhampati LLMs仍然无法规划&#xff1b;LRMs可以…

Mybatis的基本使用

什么是Mybatis&#xff1f; Mybatis是一个简化JDBC的持久层框架&#xff0c;MyBatis是一个半自动化框架&#xff0c;是因为它在SQL执行过程中只提供了基本的SQL执行功能&#xff0c;而没有像Hibernate那样将所有的ORM操作都自动化了。在MyBatis中&#xff0c;需要手动编写SQL语…

【Android】布局优化—include,merge,ViewStub的使用方法

引言 1.重要性 在Android应用开发中&#xff0c;布局是用户界面的基础。一个高效的布局不仅能提升用户体验&#xff0c;还能显著改善应用的性能。随着应用功能的复杂性增加&#xff0c;布局的优化变得尤为重要。优化布局能够减少渲染时间&#xff0c;提高响应速度&#xff0c…

Docker安装consul + go使用consul + consul知识

1. 什么是服务注册和发现 假如这个产品已经在线上运行&#xff0c;有一天运营想搞一场促销活动&#xff0c;那么我们相对应的【用户服务】可能就要新开启三个微服务实例来支撑这场促销活动。而与此同时&#xff0c;作为苦逼程序员的你就只有手动去 API gateway 中添加新增的这…