首页 > 编程语言 >【机器学习】ID3、C4.5、CART 算法

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

时间:2024-09-28 14:49:35浏览次数:8  
标签:target tree ID3 CART feature entropy C4.5 data best

目录

常见的决策树算法

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算法。


决策树的优缺点

优点:

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

缺点:

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

决策树的优化

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


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

标签:target,tree,ID3,CART,feature,entropy,C4.5,data,best
From: https://blog.csdn.net/m0_73633807/article/details/142383566

相关文章

  • 决策树之——C4.5算法及示例
    0前言本文主要讲述了决策树C4.5算法构建原理并举例说明。读者需要具备的知识有:信息熵、条件熵、信息增益、信息增益比。本文所使用的数据集为:西瓜数据集1.2节。1C4.5算法流程准备数据集:输入数据集包含多个样本,每个样本具有多个特征(属性)和一个目标类别标签。设置阈......
  • 决策树之——ID3算法及示例
    0前言本文主要介绍决策树ID3算法,并举出构建示例帮助理解。读者需要具备的知识:信息熵、条件熵、信息增益。本文使用数据集为:游玩数据集1.1节、西瓜数据集1.2节。1ID3算法简述ID3(IterativeDichotomiser3)算法是一种经典的决策树学习算法,由RossQuinlan于1986年提出。该......
  • 安装cartopy失败的处理过程,尚在等待中,成功与否不知。
    Win7,Python3.8,sublimetext,运行(build)wind-draw.py提示:ModuleNotFoundError:Nomodulenamed'cartopy'。搜索,在csdn上看到:cartopy安装保姆教程--三天的试错,终于成功了及【Cartopy】安装失败解决方案,一定可行参照安装。查:piplist,发现有pillow,无shapely、pyproj、py......
  • Cartographer的扫描匹配
    cartographer代码思想解读(1)-相关匹配cartographer在2016年开源后一直在使用,但是一直未仔细阅读并分析其核心代码结构。目前网上可以找到许多博主对其分析和理解。其cartographer的基本思想可参考他人的 博主博客。本博客主要目的根据其框架思想,将其核心算法进行提取,方便后......
  • cartographer之MapBuilder类
    node_main.cc node_main.cc--->node.cc--->map_builder_bridge.cc--->map_builder.ccnode_main.cc:cartographer_ros/cartographer_ros/cartographer_ros/node_main.cc//MapBuilder类是完整的SLAM算法类,包含前端(TransformingTrajectoryBuilder,scantosubmap)、后端(用于......
  • 决策树-ID3
    代码importnumpyasnpdata=np.array([['老年','短发','平底','深色','男性'],['老年','短发','平底','浅色','男性'],['老年','中发','......
  • 关于cartographer在github中的文件分配
    Cartographer是一个开源的库,用于2D和3D的SLAM。在Cartographer项目中,地图构建的数据传入和处理通常分布在几个不同的组件和文件夹中。以下是一些可能包含相关代码的文件夹和组件:1.**传感器驱动**(`cartographer/sensor`):这个目录包含用于处理不同类型传感器输入的代码,例如......
  • Franka Robot robot.setJointImpedance()和robot.setCartesianImpedance()两个函数有
    robot.setJointImpedance()和robot.setCartesianImpedance()两个函数有以下区别和联系:区别:参考坐标系不同setJointImpedance()是设置每个关节的阻抗参数,以关节坐标系为参考。setCartesianImpedance()是设置机器人末端在笛卡尔空间中的阻抗参数,以笛卡尔坐标系为参考。......
  • 装了一次没成功的前提下,ubuntu18.04+ros(melodic)安装 cartographer源码安装及测试---
    因为项目需要所以要安装cartographer,最开始也没仔细研究一下,随便找了一个csdn教程就跟着安装了,装了一下午,总是在最后编译的时候出错,晚上的时候心态崩了,咸鱼上找了个远程安装的,他好像是用小鱼的那个脚本安装,装了一个小时也没安装好。不死心的我又去咸鱼上找人,然后开口要两千块,两......
  • 玩转zencart自助搭建卖货商城,zencart外贸建站完全实操手册-36节课
    课程目录:1-你也可用zencart自助建站1.mp42-Zencart它能做什么1.mp43-Zencart使用所需环境和条件1.mp44-zencart环境工具xampp安装1.mp45-zencart安装演示1.mp46-模板切换不带mysql数据库1.mp47-手动配置带sql数据库模板1.mp48-网站标题关键词描述设置1.mp49-网站logo......