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的计算复杂度较高,但它在大规模数据集上表现得更好,能更好地处理复杂的分类任务。