👋大家好,我是一名正在学习机器学习的小白,最近在写一些关于机器学习基础概念的文章。如果你也对机器学习感兴趣,或者想要了解一些基础知识,欢迎来关注我哦!🤗
决策树
决策树是一种基于树形结构的分类和回归模型。它通过对数据集进行划分,构建一棵树来进行决策。每个节点代表一个特征,每个分支代表该特征的一个取值,每个叶子节点代表一个分类或回归结果。在分类问题中,决策树可以用于判断一个样本属于哪个类别;在回归问题中,决策树可以用于预测一个连续值。决策树具有易于理解、易于解释、易于实现等优点,因此被广泛应用于数据挖掘、机器学习等领域。
生成决策树的一般步骤如下:
-
收集数据:收集数据是生成决策树的第一步,需要收集有关决策问题的所有相关数据。
-
准备数据:准备数据是生成决策树的第二步,需要将收集到的数据进行处理,包括数据清洗、数据转换、数据归一化等。
-
选择属性:选择属性是生成决策树的第三步,需要根据数据集中的属性选择最佳的属性作为划分标准。
-
划分数据集:划分数据集是生成决策树的第四步,需要将数据集根据选择的属性进行划分,得到子集。
-
计算信息增益:计算信息增益是生成决策树的第五步,需要计算每个子集的信息熵,以及划分前后的信息增益。
-
递归生成决策树:递归生成决策树是生成决策树的最后一步,需要根据计算得到的信息增益,选择最佳的属性作为当前节点,然后递归生成子树,直到所有的叶子节点都是同一类别。
-
剪枝:剪枝是生成决策树的最后一步,需要对生成的决策树进行剪枝,以避免过拟合的问题。
ID3算法
ID3算法是一种用于决策树分类的算法,它基于信息熵的概念,通过计算每个特征的信息增益来选择最优特征,从而构建决策树。
ID3算法的步骤如下:
-
计算数据集的熵(entropy),公式为: H ( D ) = − ∑ i = 1 n p i log 2 p i H(D)=-\sum_{i=1}^{n}p_i\log_2p_i H(D)=−∑i=1npilog2pi,其中 n n n为类别数, p i p_i pi为第 i i i类样本在数据集中的占比。
例如,假设有一个数据集包含10个样本,其中有6个属于类别A,2个属于类别B,2个属于类别C。则该数据集的熵可以计算如下:
H ( X ) = − ( 6 10 log 2 6 10 + 2 10 log 2 2 10 + 2 10 log 2 2 10 ) ≈ 1.57 H(X)=-\left(\frac{6}{10}\log_2\frac{6}{10}+\frac{2}{10}\log_2\frac{2}{10}+\frac{2}{10}\log_2\frac{2}{10}\right) \approx 1.57 H(X)=−(106log2106+102log2102+102log2102)≈1.57
这个结果表示该数据集的不确定性较高,因为它包含多个类别,每个类别出现的概率相对较接近。
-
对于每个特征,计算其信息增益(information gain),公式为: I G ( D , f ) = H ( D ) − ∑ v = 1 V ∣ D v ∣ ∣ D ∣ H ( D v ) IG(D, f)=H(D)-\sum_{v=1}^{V}\frac{|D^v|}{|D|}H(D^v) IG(D,f)=H(D)−∑v=1V∣D∣∣Dv∣H(Dv),其中 f f f为特征, V V V为特征 f f f的取值个数, D v D^v Dv为特征 f f f取值为 v v v的样本子集, ∣ D v ∣ |D^v| ∣Dv∣为 D v D^v Dv的样本个数, ∣ D ∣ |D| ∣D∣是数据集样本个数。
信息增益是用来衡量一个特征对于分类任务的重要性的指标,它的计算方法如下:
信息增益 = 数据集的熵 − 特征的熵 \text{信息增益} = \text{数据集的熵} - \text{特征的熵} 信息增益=数据集的熵−特征的熵
其中,数据集的熵表示整个数据集的混乱程度,特征的熵表示在该特征下,数据集的混乱程度。
假设我们有一个数据集,其中包含了 10 个样本,每个样本有两个特征:颜色和形状。其中,颜色有红、绿、蓝三种取值,形状有圆、方两种取值。我们的任务是根据这两个特征将样本分为两类:好瓜和坏瓜。
样本 颜色 形状 类别 1 红 圆 坏瓜 2 红 圆 坏瓜 3 红 圆 坏瓜 4 绿 圆 好瓜 5 绿 圆 好瓜 6 蓝 圆 好瓜 7 绿 方 好瓜 8 蓝 方 坏瓜 9 绿 方 好瓜 10 蓝 方 好瓜 首先,我们需要计算数据集的熵。根据熵的定义,我们可以得到:
数据集的熵 = − 6 10 log 2 6 10 − 4 10 log 2 4 10 ≈ 0.971 \text{数据集的熵} = -\frac{6}{10}\log_2\frac{6}{10} - \frac{4}{10}\log_2\frac{4}{10} \approx 0.971 数据集的熵=−106log2106−104log2104≈0.971
接下来,我们需要计算每个特征的熵。首先,我们计算颜色的熵。根据颜色的取值,我们可以将数据集分成三个子集:
子集 颜色 类别 1 红 坏瓜 2 绿 好瓜、好瓜 3 蓝 好瓜、坏瓜、好瓜 根据子集的类别分布,我们可以得到每个子集的熵:
子集1的熵 = − 1 log 2 1 − 0 log 2 0 = 0 \text{子集1的熵} = -1\log_2 1 - 0\log_2 0 = 0 子集1的熵=−1log21−0log20=0
子集2的熵 = − 2 2 log 2 2 2 − 0 log 2 0 = 0 \text{子集2的熵} = -\frac{2}{2}\log_2\frac{2}{2} - 0\log_2 0 = 0 子集2的熵=−22log222−0log20=0
子集3的熵 = − 2 3 log 2 2 3 − 1 3 log 2 1 3 ≈ 0.918 \text{子集3的熵} = -\frac{2}{3}\log_2\frac{2}{3} - \frac{1}{3}\log_2\frac{1}{3} \approx 0.918 子集3的熵=−32log232−31log231≈0.918
根据颜色的熵的定义,我们可以得到:
颜色的熵 = 3 10 × 0 + 2 10 × 0 + 5 10 × 0.918 ≈ 0.459 \text{颜色的熵} = \frac{3}{10}\times 0 + \frac{2}{10}\times 0 + \frac{5}{10}\times 0.918 \approx 0.459 颜色的熵=103×0+102×0+105×0.918≈0.459
接下来,我们计算形状的熵。根据形状的取值,我们可以将数据集分成两个子集:
子集 形状 类别 1 圆 坏瓜、坏瓜、坏瓜、好瓜、好瓜、好瓜 2 方 好瓜、坏瓜、好瓜、好瓜 根据子集的类别分布,我们可以得到每个子集的熵:
子集1的熵 = − 3 6 log 2 3 6 − 3 6 log 2 3 6 ≈ 1 \text{子集1的熵} = -\frac{3}{6}\log_2\frac{3}{6} - \frac{3}{6}\log_2\frac{3}{6} \approx 1 子集1的熵=−63log263−63log263≈1
子集2的熵 = − 3 4 log 2 3 4 − 1 4 log 2 1 4 ≈ 0.811 \text{子集2的熵} = -\frac{3}{4}\log_2\frac{3}{4} - \frac{1}{4}\log_2\frac{1}{4} \approx 0.811 子集2的熵=−43log243−41log241≈0.811
根据形状的熵的定义,我们可以得到:
形状的熵 = 6 10 × 1 + 4 10 × 0.811 ≈ 0.971 \text{形状的熵} = \frac{6}{10}\times 1 + \frac{4}{10}\times 0.811 \approx 0.971 形状的熵=106×1+104×0.811≈0.971
最后,我们可以计算颜色和形状的信息增益:
颜色的信息增益 = 0.971 − 0.459 ≈ 0.512 \text{颜色的信息增益} = 0.971 - 0.459 \approx 0.512 颜色的信息增益=0.971−0.459≈0.512
形状的信息增益 = 0.971 − 0.971 = 0 \text{形状的信息增益} = 0.971 - 0.971 = 0 形状的信息增益=0.971−0.971=0
因此,我们可以得到结论:在这个数据集中,颜色的信息增益比形状的信息增益更大,因此颜色是更重要的特征。
-
选择信息增益最大的特征作为当前节点的划分特征,将数据集划分为若干个子集,每个子集对应一个分支。
-
对于每个子集,如果所有样本属于同一类别,则将该子集作为叶节点,否则递归地进行步骤2-3,直到所有子集都被划分为同一类别或者没有更多特征可供划分。
ID3算法的缺点包括:
-
对于连续型变量的处理不够灵活。ID3算法只能处理离散型变量,对于连续型变量需要进行离散化处理,这可能会导致信息损失。
-
对于噪声数据和缺失数据的处理不够鲁棒。ID3算法对于噪声数据和缺失数据的处理能力较弱,可能会导致决策树的不稳定性。
-
容易出现过拟合现象。ID3算法在构建决策树时,容易出现过拟合现象,即对训练数据过度拟合,导致泛化能力较差。
-
对于类别数较多的数据集,决策树的构建效率较低。ID3算法在处理类别数较多的数据集时,需要进行大量的计算,导致构建效率较低。
这些缺点主要是由于ID3算法的基本思想是贪心算法,只考虑当前节点的最优划分,而没有考虑全局最优解。因此,在实际应用中,需要根据具体情况选择合适的决策树算法。
下面是一个简单的例子,假设我们有一个数据集,其中包含5个样本,每个样本有两个特征(色泽和根蒂),以及一个类别(好瓜或坏瓜):
色泽 | 根蒂 | 类别 |
---|---|---|
青绿 | 蜷缩 | 好瓜 |
乌黑 | 蜷缩 | 好瓜 |
乌黑 | 硬挺 | 坏瓜 |
青绿 | 硬挺 | 坏瓜 |
浅白 | 蜷缩 | 坏瓜 |
首先,我们需要计算数据集的熵:
H ( D ) = − 3 5 log 2 3 5 − 2 5 log 2 2 5 = 0.971 H(D)=-\frac{3}{5}\log_2\frac{3}{5}-\frac{2}{5}\log_2\frac{2}{5}=0.971 H(D)=−53log253−52log252=0.971
然后,对于每个特征,我们需要计算其信息增益:
- 对于色泽特征:(浅白时特征的信息熵为0,所以省略)
I G ( D , 色泽 ) = 0.971 − 3 5 ( − 2 3 log 2 2 3 − 1 3 log 2 1 3 ) − 2 5 ( − 1 2 log 2 1 2 − 1 2 log 2 1 2 ) = 0.019 IG(D, 色泽)=0.971-\frac{3}{5}(-\frac{2}{3}\log_2\frac{2}{3}-\frac{1}{3}\log_2\frac{1}{3})-\frac{2}{5}(-\frac{1}{2}\log_2\frac{1}{2}-\frac{1}{2}\log_2\frac{1}{2})=0.019 IG(D,色泽)=0.971−53(−32log232−31log231)−52(−21log221−21log221)=0.019
- 对于根蒂特征:
I G ( D , 根蒂 ) = 0.971 − 3 5 ( − 1 3 log 2 1 3 − 2 3 log 2 2 3 ) − 2 5 ( − 1 2 log 2 1 2 − 1 2 log 2 1 2 ) = 0.271 IG(D, 根蒂)=0.971-\frac{3}{5}(-\frac{1}{3}\log_2\frac{1}{3}-\frac{2}{3}\log_2\frac{2}{3})-\frac{2}{5}(-\frac{1}{2}\log_2\frac{1}{2}-\frac{1}{2}\log_2\frac{1}{2})=0.271 IG(D,根蒂)=0.971−53(−31log231−32log232)−52(−21log221−21log221)=0.271
因此,根蒂特征的信息增益最大,我们选择根蒂特征作为当前节点的划分特征,将数据集划分为两个子集:
- 根蒂为蜷缩的子集:{青绿, 蜷缩, 好瓜}和{乌黑, 蜷缩, 好瓜}
- 根蒂为硬挺的子集:{乌黑, 硬挺, 坏瓜}和{青绿, 硬挺, 坏瓜}和{浅白, 蜷缩, 坏瓜}
对于根蒂为蜷缩的子集,所有样本属于同一类别(好瓜),因此将该子集作为叶节点;对于根蒂为硬挺的子集,我们需要递归地进行步骤2-3,选择信息增益最大的特征进行划分。在这个例子中,我们可以选择色泽特征作为下一个划分特征,因为它是唯一一个还没有被使用过的特征。最终得到的决策树如下:
根蒂
├── 蜷缩: 好瓜
└── 硬挺
├── 青绿
│ └── 色泽
│ ├── 浅白: 坏瓜
│ └── 青绿: 坏瓜
└── 乌黑: 坏瓜
这个决策树可以用于预测新的样本的类别。例如,如果我们有一个新的样本,它的色泽为乌黑,根蒂为蜷缩,我们可以按照决策树的路径进行判断,最终得到它的类别为好瓜。
以下是一个简单的Python实现ID3算法的示例代码:
import math
def entropy(data):
"""
计算数据集的熵
"""
count = {}
for d in data:
label = d[-1]
if label not in count:
count[label] = 0
count[label] += 1
entropy = 0
for c in count.values():
p = c / len(data)
entropy -= p * math.log2(p)
return entropy
def split_data(data, axis, value):
"""
根据给定特征和特征值划分数据集
"""
new_data = []
for d in data:
if d[axis] == value:
new_d = d[:axis] + d[axis+1:]
new_data.append(new_d)
return new_data
def choose_feature(data):
"""
选择最优特征
"""
num_features = len(data[0]) - 1
base_entropy = entropy(data)
best_info_gain = 0
best_feature = -1
for i in range(num_features):
feature_values = [d[i] for d in data]
unique_values = set(feature_values)
new_entropy = 0
for value in unique_values:
sub_data = split_data(data, i, value)
p = len(sub_data) / len(data)
new_entropy += p * entropy(sub_data)
info_gain = base_entropy - new_entropy
if info_gain > best_info_gain:
best_info_gain = info_gain
best_feature = i
return best_feature
def majority_label(labels):
"""
返回出现次数最多的标签
"""
count = {}
for label in labels:
if label not in count:
count[label] = 0
count[label] += 1
sorted_count = sorted(count.items(), key=lambda x: x[1], reverse=True)
return sorted_count[0][0]
def create_tree(data, features):
"""
创建决策树
"""
labels = [d[-1] for d in data]
if len(set(labels)) == 1:
return labels[0]
if len(data[0]) == 1:
return majority_label(labels)
best_feature = choose_feature(data)
best_feature_name = features[best_feature]
tree = {best_feature_name: {}}
del(features[best_feature])
feature_values = [d[best_feature] for d in data]
unique_values = set(feature_values)
for value in unique_values:
sub_features = features[:]
sub_data = split_data(data, best_feature, value)
tree[best_feature_name][value] = create_tree(sub_data, sub_features)
return tree
if __name__ == '__main__':
data = [
[1, 1, 'yes'],
[1, 1, 'yes'],
[1, 0, 'no'],
[0, 1, 'no'],
[0, 1, 'no'],
]
features = ['no surfacing', 'flippers']
tree = create_tree(data, features)
print(tree)
输出结果为:
{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}
这个决策树可以解释为:
- 如果没有浮出水面,则不会吸氧,预测结果为“不会游泳”;
- 如果浮出水面,则可能会吸氧,需要进一步判断是否有鳍;
- 如果有鳍,则预测结果为“会游泳”;
- 如果没有鳍,则预测结果为“不会游泳”。
C4.5算法
C4.5算法是一种决策树算法,是ID3算法的改进版本。C4.5算法在ID3算法的基础上进行了优化,主要包括以下几个方面:
-
C4.5算法能够处理连续型属性,而ID3算法只能处理离散型属性。
-
C4.5算法采用信息增益比来选择最优划分属性,而ID3算法只采用信息增益。
-
C4.5算法能够处理缺失值,而ID3算法不能处理缺失值。
-
C4.5算法采用剪枝技术来避免过拟合,而ID3算法没有剪枝技术。
C4.5算法的主要思想是通过递归地将数据集划分为更小的子集,直到所有子集都属于同一类别或者达到预定的停止条件。在划分数据集的过程中,C4.5算法采用信息增益比来选择最优划分属性,同时使用剪枝技术来避免过拟合。
C4.5算法的具体步骤如下:
- 构建决策树的根节点,将所有训练样本放入根节点。
- 对于每个非叶子节点,计算每个属性的信息增益比,选择信息增益比最大的属性作为划分属性。
- 根据划分属性将训练样本分成若干个子集,每个子集对应一个子节点。
- 对于每个子节点,如果所有训练样本都属于同一类别,则将该节点标记为叶子节点,并将该类别作为叶子节点的类别;否则,递归地对该子节点进行步骤2-4,直到所有叶子节点都被标记。
- 对生成的决策树进行剪枝,避免过拟合。
为什么要用信息增益率
信息增益的方法已经可以选出划分属性了,为什么还要有信息增益率,这不是增加大家的学习成本吗,莫非信息增益有什么缺陷?确实有缺陷。
如果各个属性的值的个数比较类似,缺陷并不明显
比如:场地{室内、室外},风力{大风、小风},属性值都只有两个
如果各个属性的值的个数差异较大,会发现信息增益偏向值个数多的属性
比如:场地{室内、室外},风力{台风、狂风、大风、小风、微风、无风},属性值一个是两个一个是六个
举个例子,如果我们把图中 id 列,也当成属性来划分,会发现计算出的信息增益比场地划分还大。这也很好理解,因为样本 id 各不相同,相当于划分后每个分支(仅有一个样本)的分类都确定了,信息增益自然最大。但这并不能反映决策树的泛化能力。所以为了纠正信息增益偏向值个数多的属性这个缺陷,C4.5 决策树提出了信息增益率。
什么是信息增益率
很容易想到,既然信息增益偏向值个数多的属性,那我们就给值多的属性进行"惩罚"。先看一下信息增益率的公式:
信息增益率计算公式为:G a i n _ r a t i o ( D , A ) = G a i n ( D , A ) I V ( A ) Gain\_ratio(D, A) = \frac{Gain(D, A)}{IV(A)} Gain_ratio(D,A)=IV(A)Gain(D,A)
其中, G a i n ( D , A ) Gain(D, A) Gain(D,A)表示数据集 D D D在属性 A A A上的信息增益, I V ( A ) IV(A) IV(A)表示属性 A A A的固有值,计算公式为:
I V ( A ) = − ∑ i = 1 n ∣ D i ∣ ∣ D ∣ log 2 ∣ D i ∣ ∣ D ∣ IV(A) = -\sum_{i=1}^{n}\frac{|D_i|}{|D|}\log_2\frac{|D_i|}{|D|} IV(A)=−i=1∑n∣D∣∣Di∣log2∣D∣∣Di∣
其中, n n n为属性 A A A的取值个数, D i D_i Di为 D D D中在属性 A A A上取值为 i i i的样本子集, ∣ D ∣ |D| ∣D∣为数据集 D D D的样本总数。
可以看出IV的公式很像熵的公式,由熵的性质可知,分布越分散熵越大,所以这里值的个数越多IV(A)越大,对于增益率分母越大值越小,所以信息增益率可以起到"惩罚"值个数多的属性的目的。
C4.5算法对于连续型属性的离散化处理主要有以下几个步骤:
-
对于每个连续型属性,将其按照从小到大的顺序排序。
-
对于每个相邻的属性值,计算其中点值,作为一个候选的分割点。
-
对于每个候选的分割点,将数据集按照该点进行分割,并计算分割后的信息增益。
-
选择信息增益最大的分割点作为最终的分割点。
-
将数据集按照最终的分割点进行分割,并将连续型属性转化为离散型属性,分别表示小于等于分割点和大于分割点两个取值。