决策树两种算法实现(ID3和C4.5)

1.ID3算法

介绍:

ID3(Iterative Dichotomiser 3)是由Ross Quinlan提出的决策树生成算法,主要用于分类问题。ID3算法的核心思想是通过选择能最大程度地“减少不确定性”的特征进行数据划分。它通过计算信息增益来评估每个特征的划分效果

核心思想:

ID3通过计算信息增益(Information Gain)来选择划分特征。信息增益是指通过某一特征的划分后,数据集的不确定性(熵)减少的程度

关键步骤:

1.计算熵

计算熵:熵是信息论中的一个重要概念,用来衡量数据集的“纯度”或“不确定性”。当数据集的类别完全相同时,熵为0,表示没有不确定性;而当类别分布完全均匀时,熵最大,表示不确定性最高

公式:

2.计算信息增益

计算信息增益: 信息增益表示通过选择某个特征进行划分,数据集的熵减少了多少。信息增益越大,表示通过这个特征划分后,数据集越“纯”

公式:

3.选择信息增益最大的特征进行划分 

选择信息增益最大的特征进行数据划分。对于每个划分的子集,重复计算熵和信息增益,直到满足终止条件(如所有数据已分类或没有特征可供进一步分裂)

优缺点:

优点:算法简单,计算速度较快,易于实现

缺点:

1.偏向性: ID3倾向于选择取值较多的特征。举个例子,如果特征“天气”有多种取值(如“晴天”,“雨天”,“雪天”),ID3可能会偏向选择这个特征,因为它有更多的取值(这种特征会带来更多的划分)。

2.不能处理连续特征: ID3只能处理离散特征,不能直接处理连续属性,需要预先离散化。

3.容易过拟合: 当数据噪声较多时,ID3可能会生成非常复杂的树,导致模型过拟合。

 代码实现:

class ID3:
    def __init__(self):
        self.tree = None  # 初始化决策树为空

    def fit(self, X, y):
        # 训练决策树模型
        self.tree = self._build_tree(X, y)

    def _build_tree(self, X, y):
        # 如果标签y中只有一个唯一值,直接返回该标签
        if len(np.unique(y)) == 1:
            return y.iloc[0]

        # 如果特征X为空,返回一个随机的标签
        if X.empty:
            return np.random.choice(y)

        # 选择最优特征进行划分
        best_feature = self._choose_best_feature(X, y)
        tree = {best_feature: {}}

        # 对于每个特征的不同取值,递归构建子树
        for value in np.unique(X[best_feature]):
            sub_X = X[X[best_feature] == value].drop(columns=[best_feature])  # 筛选出该特征值的子集
            sub_y = y[X[best_feature] == value]  # 筛选出对应的标签子集
            tree[best_feature][value] = self._build_tree(sub_X, sub_y)  # 递归构建子树
        return tree

    def _choose_best_feature(self, X, y):
        best_info_gain = -float('inf')  # 初始化信息增益为负无穷
        best_feature = None  # 初始化最优特征为None

        # 遍历所有特征,选择信息增益最大的特征
        for feature in X.columns:
            info_gain = self._information_gain(X[feature], y)
            if info_gain > best_info_gain:
                best_info_gain = info_gain
                best_feature = feature
        return best_feature

    def _information_gain(self, feature, y):
        # 计算划分前的熵
        entropy_before = self._entropy(y)
        entropy_after = 0

        # 对于特征的每个取值,计算划分后的熵
        for value in np.unique(feature):
            sub_y = y[feature == value]  # 获取该特征值对应的标签子集
            entropy_after += (len(sub_y) / len(feature)) * self._entropy(sub_y)  # 按比例计算加权熵

        # 信息增益是划分前后的熵差
        return entropy_before - entropy_after

    def _entropy(self, y):
        # 计算标签y的熵
        probs = y.value_counts(normalize=True)  # 计算标签的频率
        return -np.sum(probs * np.log2(probs))  # 根据公式计算熵

    def predict(self, X):
        # 对每一行数据进行预测
        return X.apply(self._predict_row, axis=1, tree=self.tree)

    def _predict_row(self, row, tree):
        # 如果树是字典类型,表示当前特征节点,递归继续
        if isinstance(tree, dict):
            feature = list(tree.keys())[0]  # 获取当前特征
            value = row[feature]  # 获取当前行特征值
            # 递归到树的下一层
            return self._predict_row(row, tree[feature].get(value, None))
        return tree  # 如果是叶子节点,返回预测结果

效果展示:

通过训练模型,用户输入相关特征数据:年龄段,是否有工作,是否有自己的房子和信贷情况,查看预测结果(该方式无法说明该模型的效果是否好,只是测试一下该算法下的模型)

总结:

ID3(Iterative Dichotomiser 3)是一个经典的决策树学习算法,主要用于分类任务。其核心思想是通过计算信息增益来选择最能区分数据的特征,从而进行数据的分裂。ID3使用熵来衡量数据的不确定性,并选择能够最大化信息增益的特征进行划分。尽管ID3算法简单、易于实现,并且计算效率较高,但它有一些明显的缺点,包括偏向选择取值较多的特征不能处理连续特征(需要离散化)、容易过拟合等问题。此外,ID3无法有效处理缺失值,因此它在面对复杂数据时可能会表现较差。

 2.C4.5算法

介绍:

 C4.5算法是ID3的改进版本,主要也是用于分类问题。C4.5通过引入信息增益比来选择特征,解决了ID3偏向多值特征的问题。它能够处理连续特征,通过选择最佳划分点将连续数据转化为离散特征。C4.5还引入了剪枝技术,通过后剪枝减少过拟合,提升模型的泛化能力。同时,C4.5能够处理缺失值,通过加权方式来调整缺失数据的影响。算法采用递归分裂的方式生成决策树,直到满足停止条件(如数据纯净或无更多特征可用)。C4.5相比ID3在处理复杂数据时更为有效,但也具有较高的计算复杂度,尤其在数据量较大的情况下。

核心思想:

1. 信息增益比

C4.5引入了信息增益比来替代ID3中的信息增益。信息增益比的目的是解决ID3偏向取值较多的特征问题。通过规范化信息增益,C4.5避免了过多取值的特征过度偏向的情况。

信息增益比的计算公式:

其中,Split_Info(D,A)是特征 A的分裂信息,计算公式为: 

Split_Info 衡量了特征 AAA 的取值多样性。信息增益比就是信息增益和分裂信息的比值。

2. 处理连续特征

C4.5可以处理连续特征。对于连续特征,C4.5会选择一个合适的阈值将其转化为离散特征,然后进行划分。例如,对于“温度”这一连续特征,C4.5会寻找一个阈值(如30°C),然后将温度大于30°C的数据归为一类,其他的数据归为另一类。

3. 剪枝

C4.5引入了剪枝的概念来防止过拟合。生成的决策树可能非常复杂,且容易在训练数据上过拟合,因此C4.5采用后剪枝技术,即生成决策树后,再删除一些不重要的分支(即不影响准确性的分支)。

剪枝步骤如下:

1.从树的叶子节点开始,评估每个分支的准确度。

2.如果移除某个分支后,树的准确度没有显著下降,就去掉该分支。

剪枝帮助C4.5在减少模型复杂度的同时,保持较好的泛化能力。

4. 递归分裂

C4.5使用递归分裂的方式,按照信息增益比选择最优特征进行划分。与ID3类似,C4.5会在每个子集上继续进行相同的分裂,直到所有数据都被分类,或者没有特征可以继续分裂。

优缺点:

优点:

1.支持连续特征: C4.5能够处理连续型数据,不需要手动离散化特征。

2.利用信息增益比: 解决了ID3中对多取值特征的偏向问题,使得特征选择更加合理。

3.剪枝机制: 可以有效避免过拟合,提升模型的泛化能力。

缺点:

1.计算复杂度高: 计算信息增益比和剪枝会导致算法的时间复杂度较高,尤其是在数据集非常大的时候,可能需要较长的训练时间。

2.缺少处理缺失数据的能力: 如果数据中有缺失值,C4.5的处理方式可能不如一些其他算法(如决策树的改进版CART)那么优雅。

代码实现:

class C45:
    def __init__(self):
        self.tree = None  # 初始化决策树为空

    def fit(self, X, y):
        # 训练决策树模型
        self.tree = self._build_tree(X, y)

    def _build_tree(self, X, y):
        # 如果标签y中只有一个唯一值,直接返回该标签
        if len(np.unique(y)) == 1:
            return y.iloc[0]

        # 如果特征X为空,返回一个随机的标签
        if X.empty:
            return np.random.choice(y)

        # 选择最优特征进行划分
        best_feature = self._choose_best_feature(X, y)
        tree = {best_feature: {}}

        # 对于每个特征的不同取值,递归构建子树
        for value in np.unique(X[best_feature]):
            sub_X = X[X[best_feature] == value].drop(columns=[best_feature])  # 筛选出该特征值的子集
            sub_y = y[X[best_feature] == value]  # 筛选出对应的标签子集
            tree[best_feature][value] = self._build_tree(sub_X, sub_y)  # 递归构建子树
        return tree

    def _choose_best_feature(self, X, y):
        best_info_gain_ratio = -float('inf')  # 初始化信息增益比为负无穷
        best_feature = None  # 初始化最优特征为None

        # 遍历所有特征,选择信息增益比最大的特征
        for feature in X.columns:
            info_gain_ratio = self._information_gain_ratio(X[feature], y)
            if info_gain_ratio > best_info_gain_ratio:
                best_info_gain_ratio = info_gain_ratio
                best_feature = feature
        return best_feature

    def _information_gain_ratio(self, feature, y):
        # 计算信息增益
        info_gain = self._information_gain(feature, y)
        # 计算特征的熵
        feature_entropy = self._entropy(feature)
        # 返回信息增益与特征熵的比值
        return info_gain / feature_entropy if feature_entropy != 0 else 0

    def _information_gain(self, feature, y):
        # 计算划分前的熵
        entropy_before = self._entropy(y)
        entropy_after = 0

        # 对于特征的每个取值,计算划分后的熵
        for value in np.unique(feature):
            sub_y = y[feature == value]  # 获取该特征值对应的标签子集
            entropy_after += (len(sub_y) / len(feature)) * self._entropy(sub_y)  # 按比例计算加权熵

        # 信息增益是划分前后的熵差
        return entropy_before - entropy_after

    def _entropy(self, y):
        # 计算标签y的熵
        probs = y.value_counts(normalize=True)  # 计算标签的频率
        return -np.sum(probs * np.log2(probs))  # 根据公式计算熵

    def predict(self, X):
        # 对每一行数据进行预测
        return X.apply(self._predict_row, axis=1, tree=self.tree)

    def _predict_row(self, row, tree):
        # 如果树是字典类型,表示当前特征节点,递归继续
        if isinstance(tree, dict):
            feature = list(tree.keys())[0]  # 获取当前特征
            value = row[feature]  # 获取当前行特征值
            # 递归到树的下一层
            return self._predict_row(row, tree[feature].get(value, None))
        return tree  # 如果是叶子节点,返回预测结果

效果展示:

通过训练模型,用户输入相关特征数据:年龄段,是否有工作,是否有自己的房子和信贷情况,查看预测结果(该方式无法说明该模型的效果是否好,只是测试一下该算法下的模型)

(与ID3中不是同一张图片)

总结:

C4.5是对ID3算法的改进,旨在解决ID3的局限性。C4.5同样基于信息增益,但采用信息增益比来选择特征,从而避免ID3中对于取值多的特征的偏向。C4.5可以处理连续特征,通过选择最佳的分裂点将连续数据转化为离散数据。它还引入了剪枝机制,通过后剪枝减少过拟合,提升模型的泛化能力。此外,C4.5能够处理缺失值,并在计算信息增益时加权考虑缺失数据的影响。虽然C4.5在多个方面进行了优化,并且表现优于ID3,但它的计算复杂度较高,特别是在数据量较大时。

两种方法对比:

1.在特征选择上,ID3使用信息增益来选择最优特征,但这种方法偏向选择取值较多的特征,因为信息增益较大的特征会被优先选择。而C4.5改进了这一点,使用信息增益比来选择特征,这样可以避免ID3中对多值特征的偏向,使得特征选择更为合理。

2.对于连续特征,ID3不能直接处理,而是需要将其离散化。C4.5则能够处理连续特征,通过选择一个最佳的分割点将连续数据转化为离散数据,避免了离散化过程中的信息损失。

3.在剪枝方面,ID3没有剪枝机制,因此生成的决策树可能会过拟合训练数据。C4.5则引入了后剪枝技术,它在树生成完成后,通过去除不必要的分支来减少过拟合,从而提升模型的泛化能力。

4.对于缺失值的处理,ID3在遇到缺失值时通常会丢弃含有缺失值的数据,而C4.5通过加权方式对缺失数据进行处理,避免了数据丢失对决策树构建的影响。

5.在计算复杂度上,ID3较为简单,计算复杂度较低,适合较小规模的数据集。而C4.5由于计算信息增益比和进行剪枝的需要,计算复杂度较高,适合处理更大规模、更复杂的数据集。

6.C4.5在性能上优于ID3,尤其在面对复杂数据集时,C4.5生成的树更加简洁,具有更强的鲁棒性和泛化能力。虽然C4.5的计算复杂度较高,但它在大规模数据集上表现得更好,能更好地处理复杂的分类任务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值