从理论到实践:深入解析香农熵在机器学习中的应用与计算
1. 香农熵:从“混乱”到“信息”的直觉理解
聊到机器学习,尤其是决策树、随机森林这些模型,你肯定绕不开一个词——熵。我第一次接触这个概念时,也觉得它有点玄乎,什么“不确定性”、“信息量”,听起来像是哲学讨论。但后来在项目里用它来筛选特征、构建模型,才发现这真是个实实在在的“神器”。今天,我就想抛开那些复杂的数学外壳,用最接地气的方式,和你聊聊香农熵到底是什么,以及我们怎么在机器学习里把它用起来。
你可以把熵想象成一个衡量“混乱程度”的尺子。想象一下你的书桌。如果所有东西都分门别类放好,笔在笔筒,书在书架,文件在文件夹里,那这就是一个非常“有序”、非常“确定”的状态。你想找一支红笔,立刻就知道它在哪里。这时候,我们说这个书桌系统的“熵”很低。反过来,如果你的书桌乱七八糟,书本、零食、文具、充电线全都混在一起,你想找一张上周的发票,得翻箱倒柜半天,完全不确定它会在哪个角落。这个状态就非常“混乱”,不确定性极高,对应的“熵”值也就很大。
克劳德·香农老爷子在1948年提出这个概念,初衷是为了解决通信中的信息量化问题。他发现,一条消息所包含的信息量,竟然和它的“出乎意料程度”成正比。一个必然发生的事件(比如“太阳从东边升起”),告诉你这个消息,你几乎得不到任何新信息,它的信息量(熵)就趋近于0。而一个完全随机、结果等概率的事件(比如抛一枚绝对公平的硬币),在结果揭晓前,你完全无法预测,这时揭晓结果带给你的信息量是最大的。
在机器学习里,我们处理的数据集,就可以看作是一个“系统”。比如一个猫狗图片分类的数据集。如果这个数据集里1000张图片全是猫,没有任何狗,那么这个数据集在“类别”这个维度上就非常“纯净”和“确定”。你随便抽一张图,我都能百分百确定它是猫。这个数据集的类别熵就是0。但如果这个数据集里500张是猫,500张是狗,完全混合,那你抽一张图之前,我完全猜不到是猫是狗,不确定性最大,这时候类别熵就达到了最大值。
所以,熵的核心思想就是:用数学公式(概率和对数)来精确度量这种“不确定性”或“混乱度”。理解了这一点,我们再去看它的公式和计算,就不会觉得是在看天书了。
2. 手把手计算香农熵:从公式到代码
知道了熵是衡量不确定性的,那具体怎么算呢?香农给出了一个非常优雅的公式。咱们先别看晕,我带你一步步拆解。
香农熵 H 的公式是:
H(X) = - Σ (p(xᵢ) * log₂(p(xᵢ)))
这里的 i 从1取到 n,n 是所有可能事件(或类别)的总数。p(xᵢ) 就是第 i 个事件发生的概率。
公式拆解与生活类比:
- p(xᵢ) - 概率:这是基础。比如一个水果篮里,苹果、橘子、香蕉的比例。
- log₂(p(xᵢ)) - 信息量:香农定义,一个概率为 p 的事件发生,所带来的“惊喜度”或“信息量”是 log₂(1/p)。概率越小的事件发生了,带来的信息量越大(比如买彩票中头奖)。因为 log₂(1/p) = -log₂(p),所以公式里出现了负号。
- p(xᵢ) * log₂(p(xᵢ)) - 加权信息量:不是所有事件的信息量都同等重要。一个极其罕见的事件(概率极低)虽然单次信息量大,但它发生的可能性太小了。所以我们要用它的概率 p(xᵢ) 对它自身的“信息量” log₂(p(xᵢ)) 进行加权平均。这就像计算平均成绩,要考虑每个分数段的人数比例。
- 负号与求和 Σ:由于 log₂(p) 在 p<1 时是负数,所以前面加个负号,保证最终熵值是个正数。然后把所有可能事件的这个“加权信息量”加起来,就得到了整个系统的平均不确定性——香农熵。
实战计算:抛硬币与选水果
-
案例一:公平硬币
- 事件:正面(H),反面(T)。
- 概率:p(H) = 0.5, p(T) = 0.5。
- 计算: H = - [ p(H)*log₂(p(H)) + p(T)*log₂(p(T)) ] = - [ 0.5 * log₂(0.5) + 0.5 * log₂(0.5) ] = - [ 0.5 * (-1) + 0.5 * (-1) ] = - [ -0.5 - 0.5 ] = 1 (比特)
你看,一个完全不确定的公平硬币,熵值是1比特。这是我们用底数为2的对数得到的结果,单位就是“比特”,这也是信息论中最常用的单位。
-
案例二:有偏见的硬币(魔术硬币)
- 事件:正面(H),反面(T)。
- 概率:p(H) = 0.9, p(T) = 0.1。(这硬币几乎总是正面)
- 计算: H = - [ 0.9 * log₂(0.9) + 0.1 * log₂(0.1) ] ≈ - [ 0.9 * (-0.152) + 0.1 * (-3.322) ] ≈ - [ -0.1368 - 0.3322 ] ≈ 0.469 (比特)
熵值从1降到了约0.47。因为硬币有很强的偏向性,结果的不确定性大大降低了。如果我告诉你“我抛了一次这个硬币”,你猜正面的信心会足很多,所以这个“消息”带给你的平均信息量(熵)就变小了。
-
案例三:水果篮子(多类别)
- 事件:苹果、橘子、香蕉。
- 概率:p(苹果)=0.5, p(橘子)=0.3, p(香蕉)=0.2。
- 计算: H = - [ 0.5log₂(0.5) + 0.3log₂(0.3) + 0.2log₂(0.2) ] ≈ - [ 0.5(-1) + 0.3*(-1.737) + 0.2*(-2.322) ] ≈ - [ -0.5 - 0.5211 - 0.4644 ] ≈ 1.485 (比特)
这个值介于最小熵0(如果只有一种水果)和最大熵log₂(3)≈1.585(如果三种水果等比例)之间,符合直觉。
用Python实现熵计算:
理论明白了,动手写代码才是王道。用Python计算熵非常简单。
import numpy as np
def calculate_entropy(probabilities):
"""
计算香农熵
参数:
probabilities: 一个列表或数组,包含各个类别或事件的概率
返回:
熵值(以比特为单位)
"""
# 将输入转换为numpy数组以便进行向量化运算
probs = np.array(probabilities)
# 过滤掉概率为0的情况,因为0 * log(0)在数学上定义为0
probs = probs[probs > 0]
# 核心计算公式:-Σ p * log2(p)
entropy = -np.sum(probs * np.log2(probs))
return entropy
# 测试我们上面的例子
print("公平硬币熵:", calculate_entropy([0.5, 0.5])) # 输出:1.0
print("偏见硬币熵:", calculate_entropy([0.9, 0.1])) # 输出:约0.4689955935892812
print("水果篮子熵:", calculate_entropy([0.5, 0.3, 0.2])) # 输出:约1.4854752972273344
这段代码就是公式的直接翻译。注意里面有个小技巧:probs = probs[probs > 0]。这是因为当某个概率 pᵢ 为0时,0 * log₂(0) 在数学上是未定义的,但在信息论中我们将其视为0(因为不可能发生的事件不贡献信息)。用这个过滤操作可以避免计算错误。
在实际的机器学习数据集中,我们通常不是直接拿到概率,而是拿到一堆样本的类别标签。这时,计算数据集 D 的熵,就需要先统计各个类别出现的频率来估计概率。
from collections import Counter
def entropy_from_labels(labels):
"""
从类别标签列表计算数据集的熵
参数:
labels: 一个列表,包含数据集中每个样本的类别标签
返回:
数据集的熵
"""
# 计算总样本数
total_count = len(labels)
# 如果数据集为空,熵为0
if total_count == 0:
return 0.0
# 使用Counter统计每个类别出现的次数
label_counts = Counter(labels)
# 计算每个类别的概率
probabilities = [count / total_count for count in label_counts.values()]
# 调用之前的熵计算函数
return calculate_entropy(probabilities)
# 示例:一个包含10个样本的数据集,7个猫,3个狗
labels = ['猫', '猫', '狗', '猫', '猫', '猫', '狗', '猫', '狗', '猫']
print("数据集的熵:", entropy_from_labels(labels)) # 输出:约0.8812908992306927
这个值约0.88比特,小于1比特(最大不确定性),因为猫的比例(0.7)比狗(0.3)大,数据集不是完全均匀的,所以不确定性比抛公平硬币要低一些。
3. 熵在决策树中的核心作用:信息增益与特征选择
好了,现在我们能计算一个数据集的熵了。但这在机器学习里有什么用呢?最重要的应用场景之一,就是构建决策树时的特征选择。 决策树的学习过程,本质上就是不断提出“问题”(根据某个特征进行划分),使得数据的“不确定性”(熵)下降最快的过程。这里就引出了信息增益这个关键概念。
什么是信息增益? 信息增益就是,在使用某个特征对数据集进行划分之前和之后,数据集熵的减少量。增益越大,说明用这个特征进行划分,能让数据变得越“纯净”,分类效果越好。 决策树算法(如ID3)在每一个节点,都会遍历所有可用特征,计算用每个特征划分所能获得的信息增益,然后选择增益最大的那个特征作为当前节点的划分标准。
计算信息增益的步骤:
- 计算父节点的熵:划分前,整个数据集的熵,记为 H(D)。
- 计算按特征A划分后的加权平均熵:假设特征A有 v 个不同的取值,将数据集 D 划分成 v 个子集 D₁, D₂, ..., Dᵥ。计算每个子集 Dⱼ 的熵 H(Dⱼ)。然后根据每个子集样本数占父节点样本数的比例 |Dⱼ| / |D| 进行加权求和,得到划分后的条件熵 H(D|A)。 H(D|A) = Σⱼ ( |Dⱼ| / |D| ) * H(Dⱼ)
- 计算信息增益: 信息增益(D, A) = H(D) - H(D|A)
实战案例:要不要出去玩?
假设我们有一个历史数据集,根据天气、温度、湿度、风力四个特征,决定是否出去玩(标签:是/否)。
| 编号 | 天气 | 温度 | 湿度 | 风力 | 出去玩 |
|---|---|---|---|---|---|
| 1 | 晴 | 热 | 高 | 弱 | 否 |
| 2 | 晴 | 热 | 高 | 强 | 否 |
| 3 | 阴 | 热 | 高 | 弱 | 是 |
| 4 | 雨 | 适中 | 高 | 弱 | 是 |
| 5 | 雨 | 冷 | 正常 | 弱 | 是 |
| 6 | 雨 | 冷 | 正常 | 强 | 否 |
| 7 | 阴 | 冷 | 正常 | 强 | 是 |
| 8 | 晴 | 适中 | 高 | 弱 | 否 |
| 9 | 晴 | 冷 | 正常 | 弱 | 是 |
| 10 | 雨 | 适中 | 正常 | 弱 | 是 |
| 11 | 晴 | 适中 | 正常 | 强 | 是 |
| 12 | 阴 | 适中 | 高 | 强 | 是 |
| 13 | 阴 | 热 | 正常 | 弱 | 是 |
| 14 | 雨 | 适中 | 高 | 强 | 否 |
第一步:计算根节点(整个数据集)的熵 H(D)
- 总样本数:14。
- “出去玩=是”的样本数:9。概率 p(是) = 9/14 ≈ 0.643
- “出去玩=否”的样本数:5。概率 p(否) = 5/14 ≈ 0.357
- H(D) = - [0.643 * log₂(0.643) + 0.357 * log₂(0.357)] ≈ 0.940 比特
第二步:计算按“天气”特征划分的信息增益
- 特征“天气”有三个取值:晴(5个样本)、阴(4个样本)、雨(5个样本)。
- 子集“天气=晴”:5个样本。其中“出去玩=是”有2个,“否”有3个。
- H(晴) = - [ (2/5)*log₂(2/5) + (3/5)*log₂(3/5) ] ≈ 0.971
- 子集“天气=阴”:4个样本。全部“出去玩=是”。
- H(阴) = - [ (4/4)*log₂(4/4) ] = 0 (因为概率为1,log₂(1)=0)
- 子集“天气=雨”:5个样本。其中“出去玩=是”有3个,“否”有2个。
- H(雨) = - [ (3/5)*log₂(3/5) + (2/5)*log₂(2/5) ] ≈ 0.971
- 计算条件熵 H(D|天气): *H(D|天气) = (5/14)*0.971 + (4/14)*0 + (5/14)0.971 ≈ 0.693
- 计算信息增益 Gain(D, 天气): Gain(D, 天气) = H(D) - H(D|天气) = 0.940 - 0.693 = 0.247 比特
第三步:同理计算其他特征的信息增益(过程略) 假设我们算出:
- Gain(D, 温度) ≈ 0.029 比特
- Gain(D, 湿度) ≈ 0.152 比特
- Gain(D, 风力) ≈ 0.048 比特
第四步:选择根节点特征 比较发现,“天气”特征的信息增益(0.247)最大。因此,决策树的根节点就根据“天气”来划分。这样,从根节点开始,数据集的不确定性下降得最多,树的结构最有效。
注意:信息增益有一个缺点,它倾向于选择取值较多的特征(比如“用户ID”这种特征,每个值只有一个样本,划分后每个子集熵都为0,信息增益极大,但毫无泛化能力)。为了克服这个问题,后来提出了信息增益率(C4.5算法)和基尼不纯度(CART算法)等改进指标。但无论如何,其核心思想——寻找最能降低数据不确定性的划分方式——都源于香农熵。
通过这个例子,你应该能深刻感受到,熵和信息增益不是空中楼阁的数学概念,而是驱动决策树生长的“发动机”。它用可计算的数字,告诉我们“先问哪个问题最好”。
4. 超越决策树:熵在机器学习中的广泛应用
熵的应用远不止于决策树。它作为一种衡量分布差异、不确定性和信息量的基本工具,渗透在机器学习的多个领域。
4.1 特征选择与过滤式方法
除了在决策树内部做特征选择,我们也可以直接用熵来独立评估单个特征与目标类别的相关性,这属于过滤式特征选择方法。
互信息 是其中一个非常重要的指标。它衡量的是两个随机变量之间的相互依赖程度,或者说,知道一个变量的信息后,另一个变量不确定性减少的量。它的计算基于联合概率分布和边缘概率分布的熵。
I(X; Y) = H(X) + H(Y) - H(X, Y)
其中 H(X, Y) 是联合熵。互信息越大,说明特征 X 和类别 Y 的关系越紧密。我们可以计算数据集中每个特征与目标标签的互信息,然后排序,选择互信息最高的前K个特征。Scikit-learn中就有现成的函数:
from sklearn.feature_selection import mutual_info_classif
import pandas as pd
import numpy as np
# 假设 X 是特征矩阵,y 是标签
# X = ...
# y = ...
# 计算每个特征与标签的互信息
mi_scores = mutual_info_classif(X, y, discrete_features='auto', random_state=42)
# 将结果与特征名对应起来(如果是DataFrame)
mi_df = pd.DataFrame({'feature': X.columns, 'mi_score': mi_scores})
mi_df = mi_df.sort_values('mi_score', ascending=False)
print(mi_df.head(10)) # 查看互信息最高的10个特征
这种方法计算速度快,不依赖于具体的模型,可以作为建模前特征预筛选的强力工具。
4.2 模型评估与预测不确定性
在分类模型中,尤其是像神经网络这类可以输出概率的模型,熵可以用来衡量模型对某个预测的置信度。
假设一个猫狗分类器对一个样本的预测概率为:[0.9(猫), 0.1(狗)]。另一个样本的预测概率为:[0.51(猫), 0.49(狗)]。虽然模型都把第一个类别(猫)作为预测结果,但显然第一个预测要自信得多。
我们可以计算这个概率分布的熵:
- 第一个分布熵:H ≈ -[0.9log₂(0.9)+0.1log₂(0.1)] ≈ 0.469 比特
- 第二个分布熵:H ≈ -[0.51log₂(0.51)+0.49log₂(0.49)] ≈ 0.9997 比特 ≈ 1 比特
第一个预测的熵很低,说明模型很确定;第二个预测的熵接近最大值1比特,说明模型自己也很“纠结”,这个预测结果非常不确定。 在实际系统中,我们可以设置一个熵阈值。对于预测熵高于阈值的样本,可以将其标记为“低置信度预测”,交给人工复核,或者不纳入后续的自动化流程,从而提高整体系统的可靠性。
4.3 聚类效果评估
在无监督学习的聚类中,我们没有真实的标签。但如果我们有部分先验知识,或者想评估聚类结果与某个外部标准的一致性,熵也能派上用场。
一种常用的方法是标准化互信息。假设我们通过聚类算法将数据分成了K个簇,同时数据本身有真实的类别标签C。我们可以计算聚类结果与真实类别之间的互信息 I(Cluster; Class)。为了消除聚类数目K的影响,通常会对其进行标准化,得到值域在[0,1]之间的NMI分数。NMI越高,说明聚类结果与真实类别的一致性越好。
from sklearn.metrics import normalized_mutual_info_score
# cluster_labels 是聚类算法得到的标签
# true_labels 是真实的类别标签(如果已知)
nmi_score = normalized_mutual_info_score(true_labels, cluster_labels)
print(f"标准化互信息(NMI)分数:{nmi_score:.4f}")
4.4 正则化与损失函数
在深度学习领域,熵直接进入了损失函数。交叉熵损失 是分类任务中最常用的损失函数之一。它衡量的是模型预测的概率分布与真实的标签分布之间的差异。
对于二分类问题,交叉熵损失公式为: L = - [y * log(p) + (1-y) * log(1-p)] 其中 y 是真实标签(0或1),p 是模型预测为正类的概率。
你可以把它理解为:用一个“理想的”低熵分布(真实标签,一个one-hot向量,熵为0),去衡量“预测的”概率分布的熵,同时加上两者之间的差异惩罚。 模型训练的目标就是最小化这个交叉熵,让预测分布尽可能逼近真实分布。
从最大似然估计的角度看,最小化交叉熵等价于最大化样本数据的对数似然。正是这种与信息论和统计学的深刻联系,使得交叉熵损失如此强大和普及。
4.5 探索与利用的权衡(信息增益的哲学)
甚至在强化学习领域,也能看到熵思想的影子。在智能体做决策时,会面临“探索”和“利用”的两难。如果只利用当前已知的最佳动作,可能会错过更好的选择;如果过度探索,又会降低效率。有些高级策略(如基于熵的探索)会鼓励智能体选择那些能带来更高“信息增益”的动作,即能最大程度减少环境状态不确定性的动作。这本质上和决策树选择特征的思想一脉相承——选择那个能带来最大认知收益的操作。
从我这些年的项目经验来看,理解熵不仅仅是为了通过面试或者看懂算法公式。它给你提供了一种量化“不确定性”的思维方式。当你面对一堆杂乱的数据时,你会本能地去想:“哪个特征最能帮我理清头绪?”(信息增益);当你看到一个模型的预测结果时,你会多问一句:“这个预测有多大的把握?”(预测熵);当你设计一个系统时,你会考虑:“我是否需要为那些不确定的case准备一条人工通道?”。
这种思维,是把机器学习从“调包调参”的层面,提升到“理解数据与模型本质”层面的关键一步。刚开始你可能会觉得计算熵和信息增益有点繁琐,但亲手算过几个例子,写几行代码实现之后,它就会内化成你的直觉。下次再看到决策树分裂,你脑子里大概就能浮现出熵在那一刻是如何下降的,那种感觉,就像突然看懂了魔术背后的机关,非常踏实。
更多推荐


所有评论(0)