Machine Learning Mastery 概率教程(一)
简评詹森不等式
最后更新于 2020 年 7 月 31 日
在统计学和机器学习中,创建变量的线性变换或映射是很常见的。
一个例子是特征变量的线性缩放。我们有自然的直觉,即缩放值的平均值与平均原始变量值的缩放值相同。这是有道理的。
不幸的是,当使用变量的非线性变换时,当这种关系不再成立时,我们会带着这种直觉。修复这种直觉需要发现詹森不等式,它提供了一种用于函数分析、概率和统计的标准数学工具。
在本教程中,您将发现詹森不等式。
完成本教程后,您将知道:
- 线性映射的直觉不适用于非线性函数。
- 一个变量的凸函数的均值总是大于该变量的均值的函数,称为詹森不等式。
- 不等式的一个常见应用是在对一段时间间隔内的财务回报取平均值时比较算术平均值和几何平均值。
用我的新书机器学习概率启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
- 2019 年 10 月更新:修正小错别字(感谢安迪)。
简森不等式简介 图片由 gérard 提供,保留部分权利。
教程概述
本教程分为五个部分;它们是:
- 线性映射的直觉
- 非线性映射的不等式
- 发展詹森不等式的直觉
- 算术和几何平均示例
- 其他应用
线性映射的直觉
我们经常使用一种叫做线性映射的线性函数来转换观测值。
常见的线性变换包括旋转、反射和缩放。
例如,我们可以将一组观察值乘以一个常数分数,以便对它们进行缩放。
然后,我们可以根据观察结果的真实价值和转变后的价值来工作和思考观察结果。这可能包括汇总统计数据的计算,如总和或平均值。
当处理原始状态和转换状态的观测值时,我们会有直觉,转换值的平均值与原始观测值的转换平均值相同。
我们可以用 x 表示我们的观测值, f() 表示我们的变换函数, mean() 表示计算平均值;这将是:
- 平均值(f(x)) == f(平均值(x)),对于线性 f()
我们的直觉是正确的,我们可以用一个小例子来证明。
考虑一个简单的游戏,我们掷一个公平的骰子,得到一个 1 到 6 之间的数字。我们可能每掷一次都有一个作为骰子点数 0.5 的回报。
这意味着滚动 3 将得到 3 * 0.5 或 1.5 的回报。
我们可以定义我们的支付函数如下:
# transform function
def payoff(x):
return x * 0.5
接下来,我们可以定义可能掷骰子的范围和每个值的变换:
# each possible roll of the dice
outcomes = [1, 2, 3, 4, 5, 6]
# payoff for each roll
payoffs = [payoff(value) for value in outcomes]
接下来,我们可以计算支付值的平均值,例如转换后的观测值的平均值。
# mean of the payoffs of the outcomes
v1 = mean(payoffs)
print(v1)
最后,我们可以比较平均掷骰子的收益,例如平均观测值的变换。
# payoff of the mean outcome
v2 = payoff(mean(outcomes))
print(v2)
我们希望这两个计算值总是相同的。
将这些联系在一起,完整的示例如下所示。
# example comparing mean linear transform vs linear transform for mean value
from numpy import mean
# transform function
def payoff(x):
return x * 0.5
# each possible roll of the dice
outcomes = [1, 2, 3, 4, 5, 6]
# payoff for each roll
payoffs = [payoff(value) for value in outcomes]
# mean of the payoffs of the outcomes
v1 = mean(payoffs)
print(v1)
# payoff of the mean outcome
v2 = payoff(mean(outcomes))
print(v2)
运行该示例计算两个平均值(例如,线性收益的平均值和平均值的线性收益),并确认它们在我们的示例中确实是等价的。
1.75
1.75
问题是,当变换函数是非线性的时,这种直觉不成立。
非线性映射的不等式
非线性函数是指输入和输出之间不形成直线的关系。
相反,该关系是弯曲的,例如向上弯曲,称为凸函数,或者向下弯曲,称为凹函数。通过反转函数的输出,我们可以很容易地将一个凹函数转换成一个凸函数,因此,我们通常谈论的凸函数的增长速度超过了线性。
例如,将输入平方或 f(x) == x² 的变换是二次凸函数。这是因为随着 x 的增加,变换函数 f() 的输出随着输入的平方而增加。
我们的直觉认为,变换后的观测值的平均值与平均观测值的变换相同,但这不适用于凸函数。
相反,如果变换函数是凸的并且观测值不是常数,观测值的平均变换平均值(f(x)) 总是大于平均观测值的变换 f(平均值(x)) 。我们可以这样说:
- 平均值(f(x)) >= f(平均值(x)),对于凸 f()而言,x 不是常数
这个数学规则最早是由约翰·延森描述的,通常被称为詹森不等式。
自然,如果转换函数是凹的,大于号(>)将变成小于号(
- 平均值(f(x)) <= f(平均值(x)),对于凹面 f()
这一开始并不直观,有着有趣的含义。
发展詹森不等式的直觉
我们可以试着用一个有效的例子来证明詹森的不等式直觉。
我们的掷骰子和线性支付函数的例子可以更新为具有非线性支付。
在这种情况下,我们可以使用 x² 凸函数来支付每次掷骰子的结果。例如,掷骰子三次的结果将有回报 3² 或 9。更新后的*支付()*功能如下。
# transform function
def payoff(x):
return x**2
我们可以计算每次掷骰子的收益,并将结果绘制成结果与收益的线图。
这将使我们对所有可能结果的支付函数的非线性或凸性有一种直觉。
下面列出了完整的示例。
# plot of convex payoff function
from matplotlib import pyplot
# transform function
def payoff(x):
return x**2
# each possible roll of the dice
outcomes = [1, 2, 3, 4, 5, 6]
# payoff for each roll
payoffs = [payoff(value) for value in outcomes]
# plot convex payoff function
pyplot.plot(outcomes, payoffs, label='convex')
pyplot.legend()
pyplot.show()
运行该示例计算每次掷骰子的收益,并绘制掷骰子结果与收益的关系图。
该图显示了所有可能结果的支付函数的凸形。
骰子滚动结果与凸支付函数的线图
詹森不等式表明,收益的平均值总是大于或等于平均结果的收益。
回想一下,可能结果的范围是[1,2,3,4,5,6],可能结果的平均值是 3.5,因此我们知道平均结果的回报是 3.5² 或 12.25。我们的直觉希望我们相信收益的平均值也是 12.25 左右**,但是这种直觉是错误的**。
为了证实我们的直觉是错误的,让我们将这两个值与所有可能的结果进行比较。
下面列出了完整的示例。
# example comparing mean convex transform vs convex transform for mean value
from numpy import mean
# transform function
def payoff(x):
return x**2
# each possible roll of the dice
outcomes = [1, 2, 3, 4, 5, 6]
# payoff for each roll
payoffs = [payoff(value) for value in outcomes]
# mean of the payoffs of the outcomes
v1 = mean(payoffs)
print(v1)
# payoff of the mean outcome
v2 = payoff(mean(outcomes))
print(v2)
运行这个例子,我们可以看到我们对于平均结果的回报的直觉是正确的;如我们所料,该值为 12.25。
我们可以看到直觉崩溃,平均支付值略高于 12.25。
回想一下,平均值(算术平均值)实际上只是值的总和,由值的数量归一化。现在考虑一下,如果收益,特别是[1,4,9,16,25,36],加起来是 91,我们对更大的值求和。这拉高了我们的平均值。
直觉告诉我们,因为函数是凸的,所以平均来说,转换后的值总是大于原始结果值,或者我们想要使用的任何其他求和类型的运算。
15.166666666666666
12.25
还有一个步骤可能有助于直觉,那就是取样的想法。
我们看了一个计算所有可能结果的回报的例子,但这是不寻常的。相反,我们更有可能从一个领域中抽取一些结果,并计算每个结果的收益。
我们可以通过多次掷骰子来实现这一点,例如 50 次,并计算每个结果的收益,然后将平均收益与平均结果的收益进行比较。
...
# roll the dice [1,6] many times (e.g. 50)
outcomes = randint(1, 7, 50)
直觉上,我们期望平均结果接近 3.5 的理想化值,因此平均值的回报接近 3² 或 12.25。我们还希望收益值的平均值接近 15.1。
随机性允许许多重复的结果和每个结果的重要分布,因此每次重复这个实验,收益的均值和均值的收益会有所不同。我们将重复实验 10 次。每重复一次,我们都期望不平等会持续下去。
下面列出了完整的示例。
# example of repeated trials of Jensen's Inequality
from numpy.random import randint
from numpy import mean
# transform function
def payoff(x):
return x**2
# repeated trials
n_trials = 10
n_samples = 50
for i in range(n_trials):
# roll the dice [1,6] many times (e.g. 50)
outcomes = randint(1, 7, n_samples)
# calculate the payoff for each outcome
payoffs = [payoff(x) for x in outcomes]
# calculate the mean of the payoffs
v1 = mean(payoffs)
# calculate the payoff of the mean outcome
v2 = payoff(mean(outcomes))
# confirm the expectation
assert v1 >= v2
# summarize the result
print('>%d: %.2f >= %.2f' % (i, v1, v2))
运行这个例子,我们可以看到两个平均值在试验中有相当大的变化。
注:考虑到实验的随机性,你的具体结果会有所不同。
例如,我们看到平均支付值低至 12.20,高至 16.88。我们看到平均结果的回报低至 9.36,高至 14.29。
然而,对于任何一个实验,詹森不等式都成立。
>0: 12.20 >= 9.73
>1: 14.14 >= 10.37
>2: 16.88 >= 13.84
>3: 15.68 >= 12.39
>4: 13.92 >= 11.56
>5: 15.44 >= 12.39
>6: 15.62 >= 13.10
>7: 17.50 >= 14.29
>8: 12.38 >= 9.36
>9: 15.52 >= 12.39
现在我们对詹森不等式有了一些直觉,让我们看看它被使用的一些情况。
算术和几何平均示例
詹森不等式的一个常见应用是算术平均和几何平均的比较。
回想一下,算术平均值是观察值的总和除以观察值的数量,只有当所有观察值具有相同的标度时才是合适的。
例如:
- (10 + 20) / 2 = 15
当样本观测值具有不同的尺度时,例如涉及不同的事物,则使用几何平均值。
这包括首先计算观察值的乘积,然后取的第 n 个根作为结果,其中 n 是数值的数量。对于两个值,我们将使用平方根,对于三个值,我们将使用立方根,以此类推。
例如:
- sqrt(10 * 20) = 14.14
第 n 个根也可以用 1/n 指数计算,使记法和计算更简单。因此,我们的几何平均值可以计算为:
- (10 * 20)^(1/2) = 14.14
样本值是我们的结果,第 n 个根是我们的支付函数,第 n 个根是凹函数。
有关算术平均值和几何平均值之间差异的更多信息,请参见:
乍一看,这两个函数之间的关系可能并不明显,但事实上,算术平均值也使用 n=1 的第 n 个根支付函数,这没有任何影响。
回想一下,第 n 个根和对数是彼此的反函数。如果我们首先使用第 n 个根或对数的倒数作为支付函数 f() ,我们可以更清楚地建立它们的关系。
在几何平均值或 GM 的情况下,我们正在计算对数结果的平均值:
- GM =平均值(对数(结果) )
在算术平均或调幅的情况下,我们正在计算平均结果的对数。
- AM =对数(平均值(结果) )
对数函数是凹的,因此根据我们对詹森不等式的了解,我们知道:
- 几何平均值(x) <=算术平均值(x)
在描述 AM 和 GM 的不平等时,惯例是首先列出 AM,因此,不平等可以概括为:
- 算术平均值(x) >=几何平均值(x)
或者
- 调幅> =通用
我们可以用一个小的例子来说明这一点,这个例子是我们在[1-6]中掷骰子的游戏和一个对数支付函数。
下面列出了完整的示例。
# example comparing the log geometric mean and the log arithmetic mean
from numpy import mean
from numpy import log
from matplotlib import pyplot
# transform function
def payoff(x):
return log(x)
# each possible roll of the dice
outcomes = [1, 2, 3, 4, 5, 6]
# payoff for each roll
payoffs = [payoff(value) for value in outcomes]
# mean of the payoffs of the outcomes (log gm)
gm = mean(payoffs)
# payoff of the mean outcome (log am)
am = payoff(mean(outcomes))
# print results
print('Log AM %.2f >= Log GM %.2f' % (am, gm))
# line plot of outcome vs payoff
pyplot.plot(outcomes, payoffs)
pyplot.show()
运行该示例证实了我们的预期,即对数算术平均值大于对数几何平均值。
Log AM 1.25 >= Log GM 1.10
还创建了一个所有可能结果与收益的折线图,显示了 log()函数的凹性。
显示凹函数的所有骰子结果和对数支付的线图
我们现在可以从两个平均值计算中删除日志。这可以很容易地通过对每一边或第 n 个根使用对数反函数来实现。
移除对数并用几何平均值的第 n 个根替换它给出了正常的几何平均值计算:
- 几何平均值=[1 * 2 * 3 * 4 * 5 * 6]^(1/6]
回想一下,第六根也可以通过 1/6 的指数来计算。
算术平均值可以用第一个根来计算,第一个根不做任何事情,例如指数为 1/1 或升到一次幂的平均值,因此算术平均值为:
- 算术= [1 + 2 + 3 + 4 + 5 + 6]/6
平方根函数也像对数函数一样是凹的,詹森不等式仍然成立:
- 算术平均值(x) >=几何平均值(x)
这被称为算术和几何平均的不等式,或简称为 AM-GM 不等式。
这个不等式在处理金融时间序列时很重要,比如计算收益率。
例如,平均回报率可以在一段时间间隔内计算,如一年内每月一次。它可以用算术平均值来计算,但是这个值是乐观的(一个更大的值),并且将排除回报的再投资,并且将假设任何损失将在每个时期开始时被补足。
相反,必须使用几何平均值给出区间内的实际平均收益率(较小的值),正确考虑损失、再投资和复利。
算术平均回报总是大于几何平均回报,在这种情况下,是误导。
其他应用
詹森不等式是数学中的一个有用的工具,特别是在应用领域,如概率和统计。
例如,它经常被用作数学证明的工具。
它也用于声明一个对分布知之甚少或需要知道的函数。一个例子是使用不等式来定义随机变量概率的下限。
詹森不等式也为纳西姆·塔勒布 2012 年出版的名为《T2》的反脆弱性一书中的反脆弱性思想提供了数学基础上面描述的掷骰子的凸支付函数的例子受到了本书(第十九章)一节的启发。
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
书
- 真实&复杂分析,1987。
- 不等式,1988。
- 反脆弱:从无序中获得的东西,2012。
文章
摘要
在本教程中,您发现了数学和统计中的詹森不等式。
具体来说,您了解到:
- 线性映射的直觉不适用于非线性函数。
- 一个变量的凸函数的均值总是大于该变量的均值的函数,称为詹森不等式。
- 不等式的一个常见应用是在对一段时间间隔内的财务回报取平均值时比较算术平均值和几何平均值。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
贝叶斯最优分类器的简单介绍
最后更新于 2020 年 8 月 19 日
贝叶斯最优分类器是一个概率模型,它为一个新的例子做出最可能的预测。
它是使用贝叶斯定理描述的,该定理为计算条件概率提供了一种有原则的方法。它还与最大后验概率密切相关:一种被称为 MAP 的概率框架,它为训练数据集找到最可能的假设。
实际上,贝叶斯最优分类器计算量很大,如果不是很难计算的话,相反,像吉布斯算法和朴素贝叶斯这样的简化可以用来近似结果。
在这篇文章中,您将发现贝叶斯最优分类器,用于为新的数据实例做出最准确的预测。
看完这篇文章,你会知道:
- 贝叶斯定理为计算条件概率提供了一种原则性的方法,称为后验概率。
- 最大后验概率是一个概率框架,它找到描述训练数据集的最可能的假设。
- 贝叶斯最优分类器是一种概率模型,它使用训练数据和假设空间来找到最可能的预测,从而对新的数据实例进行预测。
用我的新书机器学习概率启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
贝氏最优分类器简介 图片由内特·洛珀提供,版权所有。
概观
本教程分为三个部分;它们是:
- 贝叶斯定理
- 最大后验概率
- 贝叶斯最优分类器
贝叶斯定理
回想一下,贝叶斯定理提供了一种计算条件概率的原则性方法。
它包括计算一个结果给定另一个结果的条件概率,使用这种关系的倒数,陈述如下:
- P(A | B) = (P(B | A) * P(A)) / P(B)
我们正在计算的量通常被称为给定 B 的 A 的后验概率,而 P(A) 被称为 A 的先验概率。
可以去掉 P(B) 的归一化常数,可以证明后验与给定 A 的 B 乘以前验的概率成正比。
- P(A | B)与 P(B | A) * P(A)成正比
或者,简单地说:
- P(A | B) = P(B | A) * P(A)
这是一个有用的简化,因为我们对估计概率不感兴趣,而是对优化一个量感兴趣。一个成比例的数量就足够了。
有关贝叶斯定理主题的更多信息,请参见帖子:
既然我们已经了解了贝叶斯定理,我们也来看看最大后验概率框架。
最大后验概率
机器学习包括找到一个模型(假设)来最好地解释训练数据。
许多不同的机器学习算法背后都有两个概率框架。
它们是:
- 最大后验概率,一种贝叶斯方法。
- 最大似然估计,一种频率方法。
在机器学习的背景下,这两个框架的目标都是在给定训练数据集的情况下定位最有可能的假设。
具体来说,他们回答了这个问题:
给定训练数据,最可能的假设是什么?
这两种方法都将拟合模型的问题框定为优化问题,并涉及搜索最能描述观测数据的分布和分布参数集。
最大似然法是一种经常使用的方法,而最大似然法提供了一种贝叶斯方法。
最大化可能性的一个流行替代方法是最大化参数的贝叶斯后验概率密度。
—第 306 页,信息论,推理和学习算法,2003。
假设将贝叶斯定理简化为一个比例量,我们可以用它来估计比例假设和参数(θ)来解释我们的数据集( X ,表述如下:
- P(θ| X)= P(X |θ)* P(θ)
在θ范围内最大化这个量解决了用于估计后验概率的中心趋势(例如,分布的模型)的优化问题。
因此,这种技术被称为“最大后验估计,或简称 MAP 估计,有时简称为“最大后验估计”
- 最大化 P(X |θ)* P(θ)
关于最大后验概率主题的更多信息,请看帖子:
现在我们已经熟悉了 MAP 框架,我们可以更仔细地看看贝叶斯最优分类器的相关概念。
贝叶斯最优分类器
贝叶斯最优分类器是一种概率模型,在给定训练数据集的情况下,它对一个新的例子做出最可能的预测。
该模型也被称为贝叶斯最优学习器、贝叶斯分类器、贝叶斯最优决策边界或贝叶斯最优判别函数。
- 贝叶斯分类器:对新实例进行最可能预测的概率模型。
具体来说,贝叶斯最优分类器回答了这个问题:
给定训练数据,新实例最可能的分类是什么?
这不同于寻求最可能假设(模型)的 MAP 框架。相反,我们有兴趣做一个具体的预测。
一般来说,新实例的最可能的分类是通过结合所有假设的预测,用它们的后验概率加权得到的。
—第 175 页,机器学习,1997。
下面的等式演示了在给定假设空间( H )的情况下,给定训练数据( D ,如何计算新实例( vi )的条件概率。
- P(vj | D) =和{h 中的 H} P(vj | hi) * P(hi | D)
其中 vj 为待分类的新实例, H 为该实例分类的一组假设, hi 为给定假设, P(vj | hi) 为 vi 给定假设 hi 的后验概率, P(hi | D) 为给定数据D的假设 hi 的后验概率
选择具有最大概率的结果是贝叶斯最优分类的一个例子。
- 最大总和{h in H} P(vj | hi) * P(hi | D)
任何使用这个方程对例子进行分类的模型都是贝叶斯最优分类器,平均而言,没有其他模型能够胜过这种技术。
任何根据[等式]对新实例进行分类的系统都称为贝叶斯最优分类器,或贝叶斯最优学习器。使用相同假设空间和相同先验知识的任何其他分类方法平均来说都不能优于该方法。
—第 175 页,机器学习,1997。
我们必须接受这一点。
这是一件大事。
这意味着,平均而言,对相同数据、相同假设集和相同先验概率进行运算的任何其他算法都无法超越这种方法。因此得名“最优分类器”
尽管分类器做出了最优预测,但由于训练数据的不确定性以及问题域和假设空间的不完全覆盖,它并不完美。因此,模型会出错。这些误差通常被称为贝叶斯误差。
贝叶斯分类器产生最低可能的测试错误率,称为贝叶斯错误率。[……]贝叶斯错误率类似于不可约错误…
—第 38 页,R中应用的统计学习介绍,2017。
因为贝叶斯分类器是最优的,所以贝叶斯误差是可以产生的最小可能误差。
- 贝叶斯误差:进行预测时可能出现的最小误差。
此外,该模型通常根据分类来描述,例如贝叶斯分类器。然而,该原理同样适用于回归:即预测建模问题,其中预测数值而不是类别标签。
这是一个理论模型,但它被认为是我们可能希望追求的理想。
理论上,我们总是希望使用贝叶斯分类器来预测定性响应。但是对于真实数据,我们不知道给定 X 的 Y 的条件分布,所以计算贝叶斯分类器是不可能的。因此,贝叶斯分类器作为一个无法达到的黄金标准,可以用来与其他方法进行比较。
—第 39 页,R中应用的统计学习介绍,2017。
由于这种最优策略的计算成本,我们可以直接简化这种方法。
两种最常用的简化使用假设的采样算法,例如吉布斯采样,或者使用朴素贝叶斯分类器的简化假设。
- 吉布斯算法。基于后验概率的随机采样假设。
- 朴素贝叶斯。假设输入数据中的变量是条件独立的。
有关朴素贝叶斯主题的更多信息,请参见帖子:
然而,许多非线性机器学习算法能够做出的预测实际上是贝叶斯分类器的近似。
尽管这是一种非常简单的方法,但 KNN 通常可以生成与最佳贝叶斯分类器惊人接近的分类器。
—第 39 页,R中应用的统计学习介绍,2017。
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
邮件
书
- 第 6.7 节贝叶斯最优分类器,机器学习,1997。
- 第 2.4.2 节贝叶斯误差和噪声,机器学习基础,第二版,2018。
- 第 2.2.3 节分类设置,R中应用的统计学习介绍,2017。
- 信息论、推理和学习算法,2003。
报纸
- 多层感知器作为贝叶斯最佳鉴别函数的近似,1990。
- 基于概率分类器链的贝叶斯最优多标签分类,2010。
- 限制性贝叶斯最优分类器,2000。
- 贝叶斯分类器和贝叶斯误差,2013。
摘要
在这篇文章中,您发现了贝叶斯最优分类器,用于对新的数据实例进行最准确的预测。
具体来说,您了解到:
- 贝叶斯定理为计算条件概率提供了一种原则性的方法,称为后验概率。
- 最大后验概率是一个概率框架,它找到描述训练数据集的最可能的假设。
- 贝叶斯最优分类器是一种概率框架,它使用训练数据和假设空间来找到最可能的预测,从而为新的数据实例做出预测。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
机器学习贝叶斯定理的温和介绍
最后更新于 2019 年 12 月 4 日
贝叶斯定理为计算条件概率提供了一种有原则的方法。
这是一个看似简单的计算,尽管它可以用来轻松计算直觉经常失败的事件的条件概率。
虽然贝叶斯定理在概率领域是一个强大的工具,但在机器学习领域也有着广泛的应用。包括其在概率框架中的使用,该概率框架用于将模型拟合到训练数据集,简称为最大后验概率或最大后验概率,以及用于开发用于分类预测建模问题的模型,例如贝叶斯最优分类器和朴素贝叶斯。
在这篇文章中,你将发现计算条件概率的贝叶斯定理,以及它是如何在机器学习中使用的。
看完这篇文章,你会知道:
- 什么是贝叶斯定理,如何在真实场景中进行计算。
- 贝叶斯定理计算中的术语意味着什么以及它们背后的直觉。
- 贝叶斯定理如何用于分类器、优化和因果模型的例子。
用我的新书机器学习概率启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
- 2019 年 10 月更新:加入黑客新闻关于本教程的讨论。
- 2019 年 10 月更新:扩展添加更多贝叶斯定理的例子和用法。
机器学习贝叶斯定理的温和介绍 图片由马尔科·韦奇提供,版权所有。
概观
本教程分为六个部分;它们是:
- 条件概率的贝叶斯定理
- 命名定理中的术语
- 贝叶斯定理计算实例
- 诊断测试场景
- 手动计算
- Python 代码计算
- 二进制分类术语
- 假设建模的贝叶斯定理
- 分类的贝叶斯定理
- 朴素贝叶斯分类器
- 贝叶斯最优分类器
- 贝叶斯定理在机器学习中的更多应用
- 贝叶斯优化
- 贝叶斯信念网络
条件概率的贝叶斯定理
在我们深入研究贝叶斯定理之前,让我们回顾一下边缘概率、联合概率和条件概率。
回想一下,边缘概率是一个事件的概率,不考虑其他随机变量。如果随机变量是独立的,那么它直接是事件的概率,否则,如果变量依赖于其他变量,那么边缘概率是事件对因变量的所有结果求和的概率,称为求和规则。
- 边缘概率:一个事件的概率,与其他随机变量的结果无关,例如 P(A)。
联合概率是两个(或多个)同时发生的事件的概率,通常用来自两个相关随机变量(如 X 和 y)的事件 A 和 B 来描述。联合概率通常概括为结果,如 A 和 B
- 联合概率:两个(或多个)同时发生事件的概率,如 P(A 和 B)或 P(A,B)。
条件概率是给定另一个事件发生的情况下,一个事件发生的概率,通常用来自两个相关随机变量(如 X 和 y)的事件 A 和 B 来描述
- 条件概率:一个(或多个)事件给定另一个事件发生的概率,例如 P(A 给定 B)或 P(A | B)。
可以使用条件概率来计算联合概率;例如:
- P(A,B) = P(A | B) * P(B)
这被称为产品规则。重要的是,联合概率是对称的,这意味着:
- P(A,B) = P(B,A)
条件概率可以使用联合概率来计算;例如:
- P(A | B) = P(A,B) / P(B)
条件概率不对称;例如:
- P(A | B)!= P(B | A)
我们现在已经掌握了边缘概率、联合概率和条件概率。如果您想了解这些基础知识的更多背景知识,请参阅教程:
计算条件概率的另一种方法
现在,有另一种计算条件概率的方法。
具体而言,可以使用另一个条件概率来计算一个条件概率;例如:
- P(A|B) = P(B|A) * P(A) / P(B)
反之亦然;例如:
- P(B|A) = P(A|B) * P(B) / P(A)
这种计算条件概率的替代方法在联合概率难以计算时(大多数情况下)或者在反向条件概率可用或易于计算时都是有用的。
这种条件概率的交替计算被称为贝叶斯规则或贝叶斯定理,以第一个描述它的牧师托马斯·贝叶斯的名字命名。从语法上来说,称它为贝叶斯定理(带撇号)是正确的,但为了简单起见,省略撇号是很常见的。
- 贝叶斯定理:在没有联合概率的情况下,计算条件概率的原则性方法。
通常情况下,我们无法直接获得分母,例如 P(B)。
我们可以用另一种方法来计算它;例如:
- P(B)= P(B | A) * P(A)+P(B |不是 A)* P(不是 A)
这给出了贝叶斯定理的一个公式,我们可以使用它来替代 P(B)的计算,如下所述:
- P(A | B)= P(B | A) * P(A)/P(B | A)* P(A)+P(B |不是 A)* P(不是 A)
或者为了清楚起见,在分母周围加上括号:
- P(A | B)= P(B | A) * P(A)/(P(B | A)* P(A)+P(B |不是 A)* P(不是 A))
注:分母就是我们上面给出的展开式。
因此,如果我们有 P(A),那么我们可以计算 P(不是 A)作为它的补数;例如:
- P(非 A)= 1–P(A)
另外,如果我们有 P(不是 B |不是 A),那么我们可以计算 P(B |不是 A)作为它的补数;例如:
- P(B |不是 A)= 1–P(不是 B |不是 A)
现在我们已经熟悉了贝叶斯定理的计算,让我们更仔细地看看等式中的术语的含义。
命名定理中的术语
贝叶斯定理等式中的术语根据使用该等式的上下文来命名。
从这些不同的角度思考计算是有帮助的,有助于将你的问题映射到等式上。
首先,一般情况下,结果 P(A|B)称为后验概率,P(A)称为先验概率。
- P(A|B):后验概率。
- P(A):先验概率。
有时 P(B|A)被称为可能性,P(B)被称为证据。
- P(B|A):可能性。
- P(B):证据。
这使得贝叶斯定理可以重申为:
- 后验=可能性*先验/证据
我们可以用一个烟与火的案例来说明这一点。
假设有烟,有火的概率是多少?
其中 P(火)是先验,P(烟|火)是可能性,P(烟)是证据:
- P(火|烟)= P(烟|火)* P(火)/ P(烟)
你可以想象雨和云的情况。
现在我们已经熟悉了贝叶斯定理和术语的含义,让我们看看一个我们可以计算它的场景。
贝叶斯定理计算实例
贝叶斯定理最好用一个真实的例子来理解,用实数来演示计算。
首先,我们将定义一个场景,然后通过手动计算、Python 中的计算以及使用二进制分类领域中您可能熟悉的术语的计算来工作。
- 诊断测试场景
- 手动计算
- Python 代码计算
- 二进制分类术语
我们走吧。
诊断测试场景
贝叶斯定理的好处的一个优秀且广泛使用的例子是在医学诊断测试的分析中。
场景:考虑一个可能患有或不患有癌症(癌症为真或假)的人群,以及一个返回阳性或阴性以检测癌症的医学测试(测试为阳性或阴性),例如像检测乳腺癌的乳房 x 光检查。
问题:如果随机抽取一个患者进行检测,结果回来是阳性,那么这个患者得癌症的概率是多少?
手动计算
医学诊断测试并不完美;他们有错误。
有时病人会得癌症,但检测不会发现。这种检测癌症的能力被称为灵敏度,或真实阳性率。
在这种情况下,我们将为测试设计一个灵敏度值。测试是好的,但不是很好,真实阳性率或灵敏度为 85%。也就是说,在所有患有癌症并接受检测的人中,85%的人将从检测中获得阳性结果。
- p(测试=阳性|癌症=真)= 0.85
根据这些信息,我们的直觉会认为患者患癌症的概率为 85%。
我们对概率的直觉是错误的。
这种解释概率的错误非常普遍,以至于它有自己的名字;它被称为基本利率谬误。
它之所以有这个名字,是因为在估计一个事件的概率时的错误是由忽略基本速率引起的。也就是说,它忽略了随机选择的人患癌症的概率,而不管诊断测试的结果如何。
在这种情况下,我们可以假设乳腺癌的概率较低,并使用人为的 5000 人中有一人的基本比率值,或(0.0002) 0.02%。
- p(癌症=真)= 0.02%。
利用贝叶斯定理,我们可以正确地计算出一个病人得到阳性检测结果的概率。
让我们将场景映射到等式上:
- P(A|B) = P(B|A) * P(A) / P(B)
- P(癌症=真|测试=阳性)= P(测试=阳性|癌症=真)* P(癌症=真)/ P(测试=阳性)
我们知道给定患者患有癌症的情况下测试为阳性的概率为 85%,并且我们知道给定患者患有癌症的基础率或先验概率为 0.02%;我们可以将这些值插入:
- P(癌症=真|检验=阳性)= 0.85 * 0.0002 / P(检验=阳性)
我们不知道 P(测试=阳性),它不是直接给出的。
相反,我们可以使用以下方法进行估计:
- P(B)= P(B | A) * P(A)+P(B |不是 A)* P(不是 A)
- P(测试=阳性)= P(测试=阳性|癌症=真)* P(癌症=真)+ P(测试=阳性|癌症=假)* P(癌症=假)
首先,我们可以计算 P(癌症=假)作为 P(癌症=真)的补码,我们已经知道了
- P(癌症=假)= 1–P(癌症=真)
- = 1 – 0.0002
- = 0.9998
让我们插入我们所拥有的:
我们可以插入我们已知的值如下:
- P(检验=阳性)= 0.85 * 0.0002 + P(检验=阳性|癌症=假)* 0.9998
鉴于没有癌症,我们仍然不知道阳性检测结果的概率。
这需要额外的信息。
具体来说,我们需要知道这项测试在正确识别没有癌症的人方面有多好。也就是说,当患者没有癌症(癌症=假)时,检测阴性结果(检测=阴性),称为真阴性率或特异性。
我们将使用 95%的人为特异性值。
- p(测试=阴性|癌症=假)= 0.95
有了这最后一条信息,我们可以计算假阳性或假警报率,作为真阴性率的补充。
- P(测试=阳性|癌症=假)= 1–P(测试=阴性|癌症=假)
- = 1 – 0.95
- = 0.05
我们可以将这个误报率插入到我们的 P(测试=阳性)计算中,如下所示:
- p(检验=阳性)= 0.85 * 0.0002 + 0.05 * 0.9998
- p(测试=阳性)= 0.00017 + 0.04999
- p(测试=正)= 0.05016
太好了,所以测试返回阳性结果的概率,不管这个人有没有癌症,都在 5%左右。
我们现在有足够的信息来计算贝叶斯定理,并估计随机选择的人如果获得阳性检测结果,患癌症的概率。
- P(癌症=真|测试=阳性)= P(测试=阳性|癌症=真)* P(癌症=真)/ P(测试=阳性)
- p(癌症=真|检验=阳性)= 0.85 * 0.0002 / 0.05016
- p(癌症=真|检验=阳性)= 0.00017 / 0.05016
- p(癌症=真|测试=阳性)= 0.003389154704944
计算表明,如果患者通过这项测试被告知患有癌症,那么他们患癌症的可能性只有 0.33%。
这是一个可怕的诊断测试!
实例还表明,条件概率的计算需要足够的信息。
例如,如果我们已经有了贝叶斯定理中使用的值,我们可以直接使用它们。
这种情况很少发生,我们通常需要计算所需的位并将其插入,就像我们在本例中所做的那样。在我们的场景中,我们得到了 3 条信息,即基础率、灵敏度(或真阳性率)和特异性(或真阴性率)。
- 敏感性 : 85%的癌症患者会得到阳性检测结果。
- 基础率 : 0.02%的人有癌症。
- 特异性 : 95%没有癌症的人会得到阴性检测结果。
我们没有 P(测试=阳性),但是我们根据我们已经有的数据进行了计算。
我们可以想象,贝叶斯定理允许我们对给定的场景更加精确。例如,如果我们有更多关于患者(例如,他们的年龄)和领域(例如,年龄范围内的癌症发病率)的信息,反过来我们可以提供更准确的概率估计。
那是很多工作。
让我们看看如何使用几行 Python 代码来计算这个确切的场景。
Python 代码计算
为了使这个例子具体化,我们可以用 Python 执行计算。
下面的示例在普通 Python 中执行相同的计算(没有库),允许您使用参数并测试不同的场景。
# calculate the probability of cancer patient and diagnostic test
# calculate P(A|B) given P(A), P(B|A), P(B|not A)
def bayes_theorem(p_a, p_b_given_a, p_b_given_not_a):
# calculate P(not A)
not_a = 1 - p_a
# calculate P(B)
p_b = p_b_given_a * p_a + p_b_given_not_a * not_a
# calculate P(A|B)
p_a_given_b = (p_b_given_a * p_a) / p_b
return p_a_given_b
# P(A)
p_a = 0.0002
# P(B|A)
p_b_given_a = 0.85
# P(B|not A)
p_b_given_not_a = 0.05
# calculate P(A|B)
result = bayes_theorem(p_a, p_b_given_a, p_b_given_not_a)
# summarize
print('P(A|B) = %.3f%%' % (result * 100))
运行该示例计算患者患癌症的概率,给出的测试结果为阳性,与我们的手动计算相匹配。
P(A|B) = 0.339%
这是一个有用的小脚本,您可能想要适应新的场景。
现在,使用来自二进制分类的术语来描述场景的贝叶斯定理的计算是很常见的。它为思考问题提供了一种非常直观的方式。在下一节中,我们将回顾这些术语,看看它们如何映射到定理中的概率上,以及它们如何与我们的场景相关联。
二进制分类术语
从二进制(二级)分类中的常用术语,即特异性和敏感性的概念来自哪里,来思考癌症测试示例可能会有所帮助。
就我个人而言,我发现这些术语有助于让一切变得有意义。
首先,我们来定义一个混淆矩阵:
| Positive Class | Negative Class
Positive Prediction | True Positive (TP) | False Positive (FP)
Negative Prediction | False Negative (FN) | True Negative (TN)
然后,我们可以从混淆矩阵中定义一些比率:
- 真阳性率(TPR) = TP / (TP + FN)
- 假阳性率(FPR) = FP / (FP + TN)
- 真负速率(TNR) =总氮/(总氮+磷)
- 假阴性率(FNR) = FN / (FN + TP)
这些术语被称为利率,但也可以解释为概率。
此外,注意到以下几点可能会有所帮助:
- TPR + FNR = 1.0,或:
- fnr = 1.0–TPR
- TPR = 1.0–fnr
- TNR + FPR = 1.0,或者:
- tnr = 1.0–FPR
- FPR = 1.0–tnr
回想一下,在上一节中,我们计算了假阳性率,给出了真阴性率的补数,即 FPR = 1.0–TNR。
其中一些费率有特殊的名称,例如:
- 灵敏度= TPR
- 特异性= TNR
我们可以根据贝叶斯定理将这些比率映射到熟悉的术语上:
- P(B|A) :真阳性率(TPR)。
- P(非 B |非 A) :真阴性率(TNR)。
- P(B |不是 A) :假阳性率(FPR)。
- P(不是 B|A) :假阴性率(FNR)。
我们还可以根据熟悉的贝叶斯定理来绘制条件(类别)和治疗(预测)的基本比率:
- P(A) :正类概率(PC)。
- P(不是 A) :负类概率(NC)。
- P(B) :正预测的概率(PP)。
- P(不是 B) :否定预测的概率(NP)。
现在,让我们考虑使用这些术语的贝叶斯定理:
- P(A|B) = P(B|A) * P(A) / P(B)
- P(A|B) = (TPR * PC) / PP
我们经常不能计算 P(B),所以我们使用一个替代方案:
- P(B)= P(B | A) * P(A)+P(B |不是 A)* P(不是 A)
- P(B) = TPR * PC + FPR * NC
现在,让我们看看我们的癌症场景和癌症检测测试。
类别或状况将是“T0”癌症,治疗或预测将是“T2”测试。
首先,让我们回顾一下所有的费率:
- 真实阳性率:85%
- 假阳性率(FPR): 5%
- 真实阴性率(TNR): 95%
- 假阴性率:15%
让我们回顾一下我们对基本费率的了解:
- 阳性率:0.02%
- 负类(NC): 99.98%
- 正预测(PP): 5.016%
- 负面预测:94.984%
插一句,我们可以计算出阳性检测结果(阳性预测)的概率,即给定癌症的阳性检测结果的概率(真阳性率)乘以患癌症的基本率(阳性类别),加上没有癌症的阳性检测结果的概率(假阳性率)加上没有癌症的概率(阴性类别)。
这些术语的计算如下:
- P(B)= P(B | A) * P(A)+P(B |不是 A)* P(不是 A)
- P(B) = TPR * PC + FPR * NC
- P(B) = 85% * 0.02% + 5% * 99.98%
- P(B) = 5.016%
然后,我们可以计算该场景的贝叶斯定理,即给定阳性检测结果的癌症概率(后验概率)是给定癌症的阳性检测结果概率(真实阳性率)乘以患癌概率(阳性分类率),除以阳性检测结果概率(阳性预测)。
这些术语的计算如下:
- P(A|B) = P(B|A) * P(A) / P(B)
- P(A|B) = TPR * PC / PP
- P(A|B) = 85% * 0.02% / 5.016%
- P(A|B) = 0.339%
原来,在这种情况下,我们用贝叶斯定理计算的后验概率相当于准确率,也称混淆矩阵的正预测值(PPV):
- PPV = TP / (TP + FP)
或者,用我们的分类术语来说:
- P(A|B) = PPV
- PPV = TPR * PC / PP
那么我们为什么要不厌其烦地计算后验概率呢?
因为我们没有癌症和非癌症人群的混淆矩阵,这些人群都经过测试和未测试。相反,我们所拥有的只是一些关于我们的人口和测试的先验和概率。
这突出了我们在实践中可能选择使用计算的时候。
具体来说,当我们对所涉及的事件有信念,但我们不能通过计算现实世界中的例子来进行计算时。
假设建模的贝叶斯定理
贝叶斯定理是应用机器学习中的一个有用工具。
它提供了一种思考数据和模型之间关系的方式。
机器学习算法或模型是思考数据中结构化关系的特定方式。这样,模型可以被认为是关于数据中的关系的假设,例如输入( X )和输出( y 之间的关系。应用机器学习的实践是在给定的数据集上测试和分析不同的假设(模型)。
如果将模型视为假设的想法对您来说是新的,请参阅以下主题的教程:
贝叶斯定理提供了描述数据( D )和假设(h)之间关系的概率模型;例如:
- P(h|D) = P(D|h) * P(h) / P(D)
分解一下,它说给定假设成立或成立的概率给定一些观察到的数据可以计算为给定假设观察到数据的概率乘以假设成立的概率而不考虑数据,除以观察到数据的概率而不考虑假设。
贝叶斯定理提供了一种基于假设的先验概率、给定假设的各种观测数据的概率以及观测数据本身来计算假设概率的方法。
—第 156 页,机器学习,1997。
在这个框架下,每一个计算都有一个特定的名称;例如:
- P(h|D):假设的后验概率(我们要计算的东西)。
- P(h):假设的先验概率。
这为思考和建模机器学习问题提供了一个有用的框架。
如果我们有一些关于假设的先验领域知识,这在先验概率中被捕获。如果我们没有,那么所有的假设可能都有相同的先验概率。
如果观察到数据 P(D)的概率增加,那么给定数据 P(h|D)假设成立的概率就会降低。相反,如果假设 P(h)的概率和观察给定假设的数据的概率增加,则假设保持给定数据 P(h|D)的概率增加。
在应用机器学习中,在数据集上测试不同模型的概念可以被认为是在给定观测数据的情况下,估计每个假设(h1,h2,h3,…在 H 中)为真的概率。
建模中用最大后验概率进行优化或寻找假设,简称为最大后验或 MAP。
任何这种最大可能的假设被称为最大后验概率假设。我们可以通过使用贝叶斯定理计算每个候选假设的后验概率来确定 MAP 假设。
—第 157 页,机器学习,1997。
在这个框架下,数据(D)的概率是恒定的,因为它用于评估每个假设。因此,可以将其从计算中移除,以给出简化的非标准化估计,如下所示:
- H P(h|D)中的最大 H = P(D | H)* P(H)
如果我们没有任何关于被测试的假设的先验信息,它们可以被分配一个统一的概率,并且这个项也将是一个常数,并且可以从计算中移除,以给出以下内容:
- H P(h|D)中的最大 H = P(D | H)
也就是说,目标是找到最能解释观测数据的假设。
诸如用于预测数值的线性回归和用于二进制分类的逻辑回归的拟合模型可以在 MAP 概率框架下构建和求解。这为更常见的最大似然估计(MLE)框架提供了一种替代方案。
分类的贝叶斯定理
分类是一个预测建模问题,包括给给定的输入数据样本分配一个标签。
分类预测建模的问题可以被框架化为计算给定数据样本的类标签的条件概率,例如:
- P(类|数据)= (P(数据|类)* P(类))/ P(数据)
其中 P(类|数据)是给定所提供数据的类的概率。
可以对问题中的每个类执行该计算,并且可以选择被分配最大概率的类并将其分配给输入数据。
在实践中,计算用于分类的完全贝叶斯定理是非常具有挑战性的。
如果数据集适合代表更广泛的问题,那么类和数据的先验很容易从训练数据集中估计出来。
基于 P 类(数据|类)的观察的条件概率是不可行的,除非示例的数量非常大,例如大到足以有效地估计所有不同可能值组合的概率分布。这几乎是从来没有的情况,我们不会有足够的覆盖领域。
因此,贝叶斯定理的直接应用也变得棘手,尤其是当变量或特征的数量(n)增加时。
朴素贝叶斯分类器
将贝叶斯定理用于条件概率分类模型的解决方案是简化计算。
贝叶斯定理假设每个输入变量都依赖于所有其他变量。这是计算复杂的一个原因。我们可以去掉这个假设,将每个输入变量视为彼此独立的。
这将模型从依赖条件概率模型变为独立条件概率模型,并极大地简化了计算。
这意味着我们分别为每个输入变量计算 P(数据|类),并将结果相乘,例如:
- P(类| X1,X2,…,Xn)= P(X1 |类)* P(X2 |类)… P(Xn |类)* P(类)/ P(数据)
我们还可以降低观察数据的概率,因为它是所有计算的常数,例如:
- P(类| X1,X2,…,Xn)= P(X1 |类)* P(X2 |类)… P(Xn |类)* P(类)
贝叶斯定理的这种简化是常见的,广泛用于分类预测建模问题,通常被称为朴素贝叶斯。
单词“ naive ”是法语,通常在“I”上有一个分音符(umlaut),为了简单起见,这一点通常被省略,“Bayes”被大写,因为它是以托马斯·贝叶斯牧师的名字命名的。
有关如何在 Python 中从头实现朴素贝叶斯的教程,请参见:
贝叶斯最优分类器
贝叶斯最优分类器是一种概率模型,在给定训练数据集的情况下,它对一个新的例子做出最相似的预测。
该模型也被称为贝叶斯最优学习器、贝叶斯分类器、贝叶斯最优决策边界或贝叶斯最优判别函数。
- 贝叶斯分类器:对新实例进行最可能预测的概率模型。
具体来说,贝叶斯最优分类器回答了这个问题:
给定训练数据,新实例最有可能的分类是什么?
这不同于寻求最可能假设(模型)的 MAP 框架。相反,我们有兴趣做一个具体的预测。
下面的等式演示了在给定假设空间( H )的情况下,给定训练数据( D ,如何计算新实例( vi )的条件概率。
- P(vj | D) =和{h 中的 H} P(vj | hi) * P(hi | D)
其中 vj 为待分类的新实例, H 为该实例分类的一组假设, hi 为给定假设, P(vj | hi) 为 vi 给定假设 hi 的后验概率, P(hi | D) 为给定数据D的假设 hi 的后验概率
选择具有最大概率的结果是贝叶斯最优分类的一个例子。
任何使用这个方程对例子进行分类的模型都是贝叶斯最优分类器,平均而言,没有其他模型能够胜过这种技术。
我们必须接受这一点。这是一件大事。
因为贝叶斯分类器是最优的,所以贝叶斯误差是可以产生的最小可能误差。
- 贝叶斯误差:进行预测时可能出现的最小误差。
这是一个理论模型,但它被认为是我们可能希望追求的理想。
朴素贝叶斯分类器是一个分类器的例子,它增加了一些简化的假设,并试图逼近贝叶斯最优分类器。
有关贝叶斯最优分类器的更多信息,请参见教程:
贝叶斯定理在机器学习中的更多应用
开发分类器模型可能是贝叶斯定理在机器学习中最常见的应用。
然而,还有许多其他的应用。两个重要的例子是最优化和因果模型。
贝叶斯优化
全局优化是一个具有挑战性的问题,寻找一个输入,导致最小或最大的成本给定的目标函数。
通常,目标函数的形式复杂且难以分析,并且通常是非凸的、非线性的、高维的、有噪声的,并且评估起来计算成本高。
贝叶斯优化提供了一种基于贝叶斯定理的有原则的技术,用于指导高效且有效的全局优化问题的搜索。它的工作原理是建立一个目标函数的概率模型,称为替代函数,然后在选择候选样本对真实目标函数进行评估之前,使用获取函数对其进行有效搜索。
贝叶斯优化通常用于应用机器学习,以在验证数据集上调整给定的表现良好的模型的超参数。
有关贝叶斯优化的更多信息,包括如何从零开始实现它,请参见教程:
贝叶斯信念网络
概率模型可以定义变量之间的关系,并用于计算概率。
完全条件模型可能需要大量的数据来涵盖所有可能的情况,而概率在实践中可能难以计算。简化假设,如所有随机变量的条件独立性,可能是有效的,例如在朴素贝叶斯的情况下,尽管这是一个彻底简化的步骤。
另一种方法是开发一个模型,在所有其他情况下保持随机变量之间已知的条件相关性和条件独立性。贝叶斯网络是一种概率图形模型,它明确地捕捉图形模型中已知的有向边的条件依赖。所有缺失的连接定义了模型中的条件独立性。
因此,贝叶斯网络提供了一个有用的工具来可视化一个领域的概率模型,回顾随机变量之间的所有关系,并根据现有证据推断场景的因果概率。
根据定义,网络并不完全是贝叶斯的,尽管假设随机变量(节点)的概率分布和随机变量(边)之间的关系都是主观指定的,该模型可以被认为捕获了关于复杂域的“信念”。
有关贝叶斯信念网络的更多信息,请参见教程:
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
相关教程
- 对联合概率、边缘概率和条件概率的温和介绍
- 什么是机器学习中的假设?
- 如何在 Python 中从零开始开发朴素贝叶斯分类器
- Python 中从零开始的朴素贝叶斯分类器
- 如何在 Python 中从头实现贝叶斯优化
- 贝叶斯信念网络的温和介绍
书
文章
- 条件概率,维基百科。
- 贝叶斯定理,维基百科。
- 最大后验估计,维基百科。
- 假阳性和假阴性,维基百科。
- 基础利率谬误,维基百科。
- 敏感性和特异性,维基百科。
- 将困惑带出困惑矩阵,2016 年。
摘要
在这篇文章中,你发现了计算条件概率的贝叶斯定理,以及它是如何在机器学习中使用的。
具体来说,您了解到:
- 什么是贝叶斯定理,如何在真实场景中进行计算。
- 贝叶斯定理计算中的术语意味着什么以及它们背后的直觉。
- 贝叶斯定理如何用于分类器、优化和因果模型的例子。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
如何在 Python 中从零开始开发朴素贝叶斯分类器
最后更新于 2020 年 1 月 10 日
分类是一个预测建模问题,包括给给定的输入数据样本分配一个标签。
分类预测建模问题可以被框架化为计算给定数据样本的类标签的条件概率。贝叶斯定理为计算这种条件概率提供了一种有原则的方法,尽管实际上需要大量样本(非常大的数据集)并且计算成本很高。
相反,贝叶斯定理的计算可以通过做一些假设来简化,例如每个输入变量都独立于所有其他输入变量。虽然这是一个戏剧性的和不现实的假设,但它具有使条件概率的计算易于处理的效果,并产生了一个称为朴素贝叶斯的有效分类模型。
在本教程中,您将发现用于分类预测建模的朴素贝叶斯算法。
完成本教程后,您将知道:
- 如何将分类预测建模框架化为条件概率模型?
- 如何利用贝叶斯定理求解分类的条件概率模型?
- 如何实现简化的贝叶斯分类定理,称为朴素贝叶斯算法。
用我的新书机器学习概率启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
- 2019 年 10 月更新:修正了数学符号中的小的不一致问题。
- 2020 年 1 月更新:针对 Sklearn v0.22 API 的变化进行了更新。
如何在 Python 中从零开始开发朴素贝叶斯分类器 图片由 Ryan Dickey 提供,保留部分权利。
教程概述
本教程分为五个部分;它们是:
- 分类的条件概率模型
- 简化或朴素贝叶斯
- 如何计算先验概率和条件概率
- 朴素贝叶斯的工作示例
- 使用朴素贝叶斯的 5 个技巧
分类的条件概率模型
在机器学习中,我们经常对一个预测建模问题感兴趣,在这个问题中,我们希望为给定的观察预测一个类标签。例如,根据花的尺寸对植物种类进行分类。
这类问题被称为分类预测建模问题,与涉及预测数值的回归问题相反。模型的观察或输入称为 X ,模型的类标签或输出称为 y 。
X 和 y 一起表示从域中收集的观察值,即用于拟合模型的训练数据的表或矩阵(列和行或特征和样本)。模型必须学会如何将具体的例子映射到类标签或 y = f(X) 上,从而将错误分类的误差降到最低。
解决这个问题的一种方法是开发一个概率模型。从概率的角度来看,我们感兴趣的是在给定观察的情况下,估计类标签的条件概率。
例如,一个分类问题可能有 k 个类标签 y1,y2,…,yk 和 n 个输入变量, X1,X2,…,Xn 。我们可以为每个列计算带有给定实例或一组输入值的类标签的条件概率 x1,x2,…,xn ,如下所示:
- P(yi | x1、x2、…、xn)
然后,可以为问题中的每个类别标签计算条件概率,具有最高概率的标签可以作为最可能的分类返回。
条件概率可以使用联合概率来计算,尽管这很难处理。贝叶斯定理提供了一种计算条件概率的原则性方法。
贝叶斯定理的简单计算形式如下:
- P(A|B) = P(B|A) * P(A) / P(B)
其中我们对计算 P(A|B)感兴趣的概率称为后验概率,事件 P(A)的边缘概率称为先验概率。
我们可以用贝叶斯定理将分类框架为一个条件分类问题,如下所示:
- P(yi | x1,x2,…,xn) = P(x1,x2,…,xn | yi) * P(yi) / P(x1,x2,…,xn)
先验的 P(yi) 很容易从数据集中估计,但是基于类 P(x1,x2,…,xn | yi) 的观测的条件概率是不可行的,除非例子的数量非常大,例如大到足以有效地估计所有不同可能值组合的概率分布。
因此,贝叶斯定理的直接应用也变得难以处理,尤其是当变量或特征的数量( n )增加时。
简化或朴素贝叶斯
将贝叶斯定理用于条件概率分类模型的解决方案是简化计算。
贝叶斯定理假设每个输入变量都依赖于所有其他变量。这是计算复杂的一个原因。我们可以去掉这个假设,将每个输入变量视为彼此独立的。
这将模型从依赖条件概率模型变为独立条件概率模型,并极大地简化了计算。
首先,从计算 P(x1,x2,…,xn) 中移除分母,因为它是用于计算给定实例的每个类的条件概率的常数,并且具有归一化结果的效果。
- P(yi | x1,x2,…,xn) = P(x1,x2,…,xn | yi) * P(yi)
接下来,给定类别标签的所有变量的条件概率被改变为给定类别标签的每个变量值的单独的条件概率。然后将这些独立的条件变量相乘。例如:
- P(yi | x1,x2,…,xn)= P(x1 | yi)* P(x2 | yi)…P(xn | yi) P(yi)
可以对每个类标签执行该计算,并且可以选择具有最大概率的标签作为给定实例的分类。这个决策规则被称为最大后验概率决策规则。
贝叶斯定理的这种简化是常见的,广泛用于分类预测建模问题,通常被称为朴素贝叶斯。
“天真”一词是法语,通常在“我”的前面加上一个“T2”分音符“T3”(umlaut),为了简单起见,这个词通常被省略了,“贝叶斯”被大写,因为它是以“T4”牧师托马斯·贝叶斯的名字命名的。
如何计算先验概率和条件概率
现在我们知道了什么是朴素贝叶斯,我们可以更仔细地看看如何计算方程的元素。
先验概率的计算很简单。可以通过将训练数据集中具有类标签的观察频率除以训练数据集中的示例(行)总数来估计。例如:
- P(yi) =有 yi 的例子/全部例子
给定类别标签的特征值的条件概率也可以从数据中估计。具体来说,属于给定类的那些数据示例,以及每个变量的一个数据分布。这意味着如果存在 K 类和 n 变量,那么 k * n 不同的概率分布必须被创建和维护。
根据每个功能的数据类型,需要不同的方法。具体而言,数据用于估计三个标准概率分布之一的参数。
对于分类变量,如计数或标签,可以使用多项式分布。如果变量是二进制的,如是/否或真/假,可以使用二项式分布。如果变量是数值型的,如测量值,通常使用高斯分布。
- 二元:二项式分布。
- 分类:多项式分布。
- 数值:高斯分布。
这三个分布非常常见,以至于朴素贝叶斯实现经常以分布命名。例如:
- 二项朴素贝叶斯:使用二项分布的朴素贝叶斯。
- 多项式朴素贝叶斯:使用多项式分布的朴素贝叶斯。
- 高斯朴素贝叶斯:使用高斯分布的朴素贝叶斯。
输入变量具有混合数据类型的数据集可能需要为每个变量选择不同类型的数据分布。
使用三种常见发行版中的一种并不是强制性的;例如,如果已知实值变量具有不同的特定分布,例如指数分布,则可以使用该特定分布来代替。如果实值变量没有定义明确的分布,如双峰或多峰,则可以使用核密度估计器来估计概率分布。
朴素贝叶斯算法被证明是有效的,因此在文本分类任务中很受欢迎。文档中的单词可以被编码为二进制(单词存在)、计数(单词出现)或频率(tf/idf)输入向量以及分别使用的二进制、多项式或高斯概率分布。
朴素贝叶斯的工作示例
在本节中,我们将通过一个机器学习数据集上的小例子来具体说明朴素贝叶斯计算。
我们可以使用 Sklearn API 中的 make_blobs()函数生成一个小的人为二进制(2 类)分类问题。
下面的示例生成了 100 个带有两个数字输入变量的示例,每个变量被分配了两个类中的一个。
# example of generating a small classification dataset
from sklearn.datasets import make_blobs
# generate 2d classification dataset
X, y = make_blobs(n_samples=100, centers=2, n_features=2, random_state=1)
# summarize
print(X.shape, y.shape)
print(X[:5])
print(y[:5])
运行该示例会生成数据集并汇总大小,从而确认数据集是按预期生成的。
“ random_state ”参数设置为 1,确保每次运行代码时生成相同的随机观察样本。
前五个示例的输入和输出元素也被打印出来,显示了两个输入变量实际上是数字,每个示例的类标签不是 0 就是 1。
(100, 2) (100,)
[[-10.6105446 4.11045368]
[ 9.05798365 0.99701708]
[ 8.705727 1.36332954]
[ -8.29324753 2.35371596]
[ 6.5954554 2.4247682 ]]
[0 1 1 0 1]
我们将使用高斯概率分布对数字输入变量建模。
这可以使用规范的 SciPy API 来实现。首先,可以通过指定分布的参数(例如,平均值和标准偏差)来构建分布,然后可以使用范数. pdf()函数对特定值的概率密度函数进行采样。
我们可以使用*均值()*和 std() NumPy 函数从数据集中估计分布参数。
下面的 fit_distribution() 函数获取一个变量的数据样本,并拟合一个数据分布。
# fit a probability distribution to a univariate data sample
def fit_distribution(data):
# estimate parameters
mu = mean(data)
sigma = std(data)
print(mu, sigma)
# fit distribution
dist = norm(mu, sigma)
return dist
回想一下,我们对每个输入变量的条件概率感兴趣。这意味着我们需要每个输入变量有一个分布,每个类标签有一组分布,或者总共有四个分布。
首先,我们必须为每个类标签将数据分成样本组。
...
# sort data into classes
Xy0 = X[y == 0]
Xy1 = X[y == 1]
print(Xy0.shape, Xy1.shape)
然后,我们可以使用这些组来计算属于每个组的数据样本的先验概率。
这将是 50%,假设我们已经在两个类中创建了相同数量的例子;然而,我们将计算这些先验的完整性。
...
# calculate priors
priory0 = len(Xy0) / len(X)
priory1 = len(Xy1) / len(X)
print(priory0, priory1)
最后,我们可以调用我们定义的 fit_distribution() 函数,为每个变量、每个类标签准备一个概率分布。
...
# create PDFs for y==0
X1y0 = fit_distribution(Xy0[:, 0])
X2y0 = fit_distribution(Xy0[:, 1])
# create PDFs for y==1
X1y1 = fit_distribution(Xy1[:, 0])
X2y1 = fit_distribution(Xy1[:, 1])
将所有这些联系在一起,数据集的完整概率模型如下所示。
# summarize probability distributions of the dataset
from sklearn.datasets import make_blobs
from scipy.stats import norm
from numpy import mean
from numpy import std
# fit a probability distribution to a univariate data sample
def fit_distribution(data):
# estimate parameters
mu = mean(data)
sigma = std(data)
print(mu, sigma)
# fit distribution
dist = norm(mu, sigma)
return dist
# generate 2d classification dataset
X, y = make_blobs(n_samples=100, centers=2, n_features=2, random_state=1)
# sort data into classes
Xy0 = X[y == 0]
Xy1 = X[y == 1]
print(Xy0.shape, Xy1.shape)
# calculate priors
priory0 = len(Xy0) / len(X)
priory1 = len(Xy1) / len(X)
print(priory0, priory1)
# create PDFs for y==0
X1y0 = fit_distribution(Xy0[:, 0])
X2y0 = fit_distribution(Xy0[:, 1])
# create PDFs for y==1
X1y1 = fit_distribution(Xy1[:, 0])
X2y1 = fit_distribution(Xy1[:, 1])
运行该示例首先将数据集分成两组用于两个类标签,并确认每组的大小是均匀的,优先级是 50%。
然后为每个类别标签的每个变量准备概率分布,并报告每个分布的平均值和标准偏差参数,确认分布不同。
(50, 2) (50, 2)
0.5 0.5
-1.5632888906409914 0.787444265443213
4.426680361487157 0.958296071258367
-9.681177100524485 0.8943078901048118
-3.9713794295185845 0.9308177595208521
接下来,我们可以使用准备好的概率模型进行预测。
每个类别标签的独立条件概率可以使用该类别的先验(50%)和每个变量的值的条件概率来计算。
给定每个变量的先验和条件概率分布,下面的*概率()*函数对一个输入示例(两个值的数组)执行该计算。返回的值是一个分数,而不是一个概率,因为数量没有标准化,这是在实现朴素贝叶斯时经常执行的一个简化。
# calculate the independent conditional probability
def probability(X, prior, dist1, dist2):
return prior * dist1.pdf(X[0]) * dist2.pdf(X[1])
我们可以用这个函数来计算一个例子属于每个类的概率。
首先,我们可以选择一个例子进行分类;在这种情况下,数据集中的第一个示例。
...
# classify one example
Xsample, ysample = X[0], y[0]
接下来,我们可以计算属于第一类的例子的分数,然后是第二类,然后报告结果。
...
py0 = probability(Xsample, priory0, distX1y0, distX2y0)
py1 = probability(Xsample, priory1, distX1y1, distX2y1)
print('P(y=0 | %s) = %.3f' % (Xsample, py0*100))
print('P(y=1 | %s) = %.3f' % (Xsample, py1*100))
分数最大的班级将成为最终的分类。
将这些联系在一起,下面列出了拟合朴素贝叶斯模型并使用它进行预测的完整示例。
# example of preparing and making a prediction with a naive bayes model
from sklearn.datasets import make_blobs
from scipy.stats import norm
from numpy import mean
from numpy import std
# fit a probability distribution to a univariate data sample
def fit_distribution(data):
# estimate parameters
mu = mean(data)
sigma = std(data)
print(mu, sigma)
# fit distribution
dist = norm(mu, sigma)
return dist
# calculate the independent conditional probability
def probability(X, prior, dist1, dist2):
return prior * dist1.pdf(X[0]) * dist2.pdf(X[1])
# generate 2d classification dataset
X, y = make_blobs(n_samples=100, centers=2, n_features=2, random_state=1)
# sort data into classes
Xy0 = X[y == 0]
Xy1 = X[y == 1]
# calculate priors
priory0 = len(Xy0) / len(X)
priory1 = len(Xy1) / len(X)
# create PDFs for y==0
distX1y0 = fit_distribution(Xy0[:, 0])
distX2y0 = fit_distribution(Xy0[:, 1])
# create PDFs for y==1
distX1y1 = fit_distribution(Xy1[:, 0])
distX2y1 = fit_distribution(Xy1[:, 1])
# classify one example
Xsample, ysample = X[0], y[0]
py0 = probability(Xsample, priory0, distX1y0, distX2y0)
py1 = probability(Xsample, priory1, distX1y1, distX2y1)
print('P(y=0 | %s) = %.3f' % (Xsample, py0*100))
print('P(y=1 | %s) = %.3f' % (Xsample, py1*100))
print('Truth: y=%d' % ysample)
运行该示例首先像以前一样准备先验概率和条件概率,然后使用它们为一个示例进行预测。
属于 y=0 的例子的得分约为 0.3(回想一下这是一个非标准化的概率),而属于 y=1 的例子的得分为 0.0。因此,我们将该示例归类为属于 y=0 。
在这种情况下,真实或实际的结果是已知的, y=0 ,这与我们的朴素贝叶斯模型的预测相匹配。
P(y=0 | [-0.79415228 2.10495117]) = 0.348
P(y=1 | [-0.79415228 2.10495117]) = 0.000
Truth: y=0
在实践中,使用朴素贝叶斯算法的优化实现是一个好主意。Sklearn 库提供了三种实现,三种主要概率分布各一种;例如,二项式、多项式和高斯分布输入变量分别为 BernoulliNB 、多项式 B 和高斯分布输入变量。
为了使用 Sklearn 朴素贝叶斯模型,首先定义模型,然后将其拟合到训练数据集上。一旦拟合,概率可以通过 predict_proba() 函数预测,类标签可以通过 predict() 函数直接预测。
下面列出了将高斯朴素贝叶斯模型(GaussianNB)拟合到同一测试数据集的完整示例。
# example of gaussian naive bayes
from sklearn.datasets import make_blobs
from sklearn.naive_bayes import GaussianNB
# generate 2d classification dataset
X, y = make_blobs(n_samples=100, centers=2, n_features=2, random_state=1)
# define the model
model = GaussianNB()
# fit the model
model.fit(X, y)
# select a single sample
Xsample, ysample = [X[0]], y[0]
# make a probabilistic prediction
yhat_prob = model.predict_proba(Xsample)
print('Predicted Probabilities: ', yhat_prob)
# make a classification prediction
yhat_class = model.predict(Xsample)
print('Predicted Class: ', yhat_class)
print('Truth: y=%d' % ysample)
运行该示例使模型适合训练数据集,然后对我们在前面示例中使用的第一个示例进行预测。
在这种情况下,该示例属于 y=0 的概率为 1.0 或确定性。 y=1 的概率是一个非常小的接近 0.0 的值。
最后,直接预测类标签,再次匹配示例的基本事实。
Predicted Probabilities: [[1.00000000e+00 5.52387327e-30]]
Predicted Class: [0]
Truth: y=0
使用朴素贝叶斯的 5 个技巧
本节列出了使用朴素贝叶斯模型时的一些实用技巧。
1.对复杂分布使用 KDE
如果变量的概率分布复杂或未知,最好使用核密度估计器或 KDE 直接从数据样本中近似分布。
高斯 KDE 就是一个很好的例子。
2.随着变量依赖性的增加,表现下降
根据定义,朴素贝叶斯假设输入变量相互独立。
这在大多数时候都很有效,即使一些或大部分变量实际上是依赖的。然而,输入变量越依赖,算法的表现就越差。
3.用对数避免数字下溢
一个类标签的一个例子的独立条件概率的计算包括将多个概率相乘,一个概率用于该类,一个概率用于每个输入变量。因此,许多小数字相乘在数字上可能会变得不稳定,尤其是当输入变量的数量增加时。
为了克服这个问题,通常将计算从概率的乘积改为对数概率的和。例如:
- P(yi | x1,x2,…,xn)= log(P(x1 | y1))+log(P(x2 | y1))+…log(P(xn | y1))+log(P(yi))
计算概率的自然对数具有产生更大(负)数字的效果,并且将这些数字相加将意味着更大的概率将更接近于零。仍然可以比较结果值并将其最大化,以给出最可能的类别标签。
当概率相乘时,这通常被称为对数技巧。
4.更新概率分布
随着新数据的出现,使用新数据和旧数据来更新每个变量概率分布的参数估计值会变得相对简单。
这允许模型容易地利用新数据或随着时间变化的数据分布。
5.用作生成模型
概率分布将总结每个类别标签的每个输入变量值的条件概率。
除了在分类模型中使用之外,这些概率分布可能更普遍地有用。
例如,可以对准备好的概率分布进行随机采样,以创建新的可信数据实例。假设的条件独立性假设可能意味着,基于数据集中输入变量之间实际存在的相互依赖程度,这些示例或多或少是可信的。
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
教程
书
- 机器学习,1997。
- 机器学习:概率视角,2012。
- 模式识别与机器学习,2006。
- 数据挖掘:实用机器学习工具与技术,第 4 版,2016。
应用程序接口
- sklearn . dataset . make _ blobs API。
- scipy . stat .规范 API 。
- 朴素贝叶斯,sci kit-学习文档。
- 硬化。幼稚 _bayes。高斯乙 API〔t1〕
文章
摘要
在本教程中,您发现了用于分类预测建模的朴素贝叶斯算法。
具体来说,您了解到:
- 如何将分类预测建模框架化为条件概率模型?
- 如何利用贝叶斯定理求解分类的条件概率模型?
- 如何实现简化的贝叶斯分类定理,称为朴素贝叶斯算法。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
机器学习的连续概率分布
最后更新于 2019 年 9 月 25 日
连续随机变量的概率可以用连续概率分布来概括。
连续概率分布在机器学习中遇到,最显著的是在模型的数值输入和输出变量的分布中,以及在模型产生的误差的分布中。在许多机器学习模型执行的密度和参数估计中,通常也需要正态连续概率分布的知识。
因此,连续概率分布在应用机器学习中起着重要作用,从业者必须了解一些分布。
在本教程中,您将发现机器学习中使用的连续概率分布。
完成本教程后,您将知道:
- 连续随机变量的结果概率可以用连续概率分布来概括。
- 如何从常见的连续概率分布中参数化、定义和随机采样。
- 如何为常见的连续概率分布创建概率密度和累积密度图?
用我的新书机器学习概率启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
机器学习的连续概率分布 图片由土地管理局提供,保留部分权利。
教程概述
本教程分为四个部分;它们是:
- 连续概率分布
- 正态分布
- 指数分布
- 帕累托分布
连续概率分布
随机变量是由随机过程产生的量。
连续随机变量是具有真实数值的随机变量。
连续随机变量的每个数值结果都可以被赋予一个概率。
连续随机变量的事件与其概率之间的关系称为连续概率分布,由概率密度函数或简称为 PDF 来概括。
与离散随机变量不同,给定连续随机变量的概率不能直接指定;相反,它被计算为特定结果周围微小间隔的积分(曲线下的面积)。
事件等于或小于给定值的概率由累积分布函数(简称 CDF)定义。CDF 的倒数称为百分点函数,它将给出小于或等于概率的离散结果。
- PDF :概率密度函数,返回给定连续结果的概率。
- CDF :累积分布函数,返回小于等于给定结果的概率值。
- PPF :百分点函数,返回小于等于给定概率的离散值。
有许多常见的连续概率分布。最常见的是正态概率分布。实际上,所有感兴趣的连续概率分布都属于所谓的指数族分布,它们只是参数化概率分布(例如,基于参数值变化的分布)的集合。
连续概率分布在机器学习中扮演着重要的角色,从输入变量到模型的分布,模型产生的误差的分布,以及在模型本身中,当估计输入和输出之间的映射时。
在接下来的几节中,我们将仔细研究一些更常见的连续概率分布。
正态分布
正态分布也称为高斯分布(以卡尔·弗里德里希·高斯命名)或钟形曲线分布。
该分布涵盖了来自许多不同问题领域的实值事件的概率,使其成为一个常见且众所周知的分布,因此得名“ normal ”具有正态分布的连续随机变量称为“正态或“正态分布”
具有正常分布事件的域的一些示例包括:
- 人的高度。
- 婴儿的体重。
- 考试表现。
可以使用两个参数来定义分布:
- 均值 ( 亩):期望值。
- 方差 ( sigma² ):均值的离差。
通常,使用标准偏差代替方差,方差计算为方差的平方根,例如归一化。
- 标准差 ( 西格玛):平均值与平均值的偏差。
均值为零、标准差为 1 的分布称为标准正态分布,为了便于解释和比较,通常会将数据简化或标准化为。
我们可以定义一个均值为 50、标准差为 5 的分布,并从这个分布中抽取随机数。我们可以使用正常()NumPy 功能来实现。
下面的示例从这个分布中采样并打印了 10 个数字。
# sample a normal distribution
from numpy.random import normal
# define the distribution
mu = 50
sigma = 5
n = 10
# generate the sample
sample = normal(mu, sigma, n)
print(sample)
运行该示例将打印从定义的正态分布中随机采样的 10 个数字。
[48.71009029 49.36970461 45.58247748 51.96846616 46.05793544 40.3903483
48.39189421 50.08693721 46.85896352 44.83757824]
可以通过绘制数据样本并检查熟悉的正常形状或使用统计测试来检查数据样本是否随机。如果一个随机变量的观测值样本是正态分布的,那么它们可以用平均值和方差来概括,直接对样本进行计算。
我们可以使用概率密度函数来计算每次观测的概率。这些值的图表会给我们一个钟形的提示。
我们可以使用范数()SciPy 函数定义一个正态分布,然后计算诸如矩、PDF、CDF 等属性。
下面的示例计算我们的分布中 30 到 70 之间的整数值的概率,并绘制结果,然后对累积概率进行同样的操作。
# pdf and cdf for a normal distribution
from scipy.stats import norm
from matplotlib import pyplot
# define distribution parameters
mu = 50
sigma = 5
# create distribution
dist = norm(mu, sigma)
# plot pdf
values = [value for value in range(30, 70)]
probabilities = [dist.pdf(value) for value in values]
pyplot.plot(values, probabilities)
pyplot.show()
# plot cdf
cprobs = [dist.cdf(value) for value in values]
pyplot.plot(values, cprobs)
pyplot.show()
运行该示例首先计算[30,70]范围内整数的概率,并创建一个值和概率的线图。
该图显示了高斯或钟形,最高概率峰值在期望值或平均值 50 附近,概率约为 8%。
事件对概率或正态分布概率密度函数的线图
然后计算相同范围内观测值的累积概率,表明在平均值时,我们已经覆盖了约 50%的期望值,在与平均值有约 65 或 3 个标准偏差(50 + (3 * 5))后,我们已经非常接近 100%。
事件的线图与正态分布的累积概率或累积密度函数的关系
事实上,正态分布有一个启发式或经验法则,它通过平均值的标准偏差数来定义给定范围所覆盖的数据百分比。它被称为 68-95-99.7 规则,它是由 1、2 和 3 个标准差定义的范围所覆盖的数据与平均值的近似百分比。
例如,在我们的分布中,平均值为 50,标准偏差为 5,我们预计 95%的数据将被平均值的 2 个标准偏差,或 50 –( 2 * 5)和 50 + (2 * 5)或 40 到 60 之间的值覆盖。
我们可以通过使用百分点函数计算精确值来证实这一点。
中间的 95%将由低端 2.5%和高端 97.5%的百分点函数值来定义,其中 97.5–2.5 表示中间的 95%。
下面列出了完整的示例。
# calculate the values that define the middle 95%
from scipy.stats import norm
# define distribution parameters
mu = 50
sigma = 5
# create distribution
dist = norm(mu, sigma)
low_end = dist.ppf(0.025)
high_end = dist.ppf(0.975)
print('Middle 95%% between %.1f and %.1f' % (low_end, high_end))
运行这个例子给出了精确的结果,定义了中间 95%的预期结果,非常接近我们基于标准偏差的启发式算法 40 和 60。
Middle 95% between 40.2 and 59.8
一个重要的相关分布是对数正态概率分布。
指数分布
指数分布是一个连续的概率分布,其中少数结果最有可能,而所有其他结果的概率迅速下降。
对于离散随机变量,它是等效于几何概率分布的连续随机变量。
具有指数分布事件的域的一些示例包括:
- 点击盖革计数器的间隔时间。
- 零件失效前的时间。
- 贷款违约前的时间。
可以使用一个参数定义分布:
- 标度 ( 贝塔):分布的均值和标准差。
有时,用参数λ或速率更正式地定义分布。β参数定义为λ参数的倒数(β= 1/λ
- 速率(λ)=分布的变化速率。
我们可以定义一个平均值为 50 的分布,并从这个分布中抽取随机数。我们可以使用指数()NumPy 函数来实现这一点。
下面的示例从这个分布中采样并打印了 10 个数字。
# sample an exponential distribution
from numpy.random import exponential
# define the distribution
beta = 50
n = 10
# generate the sample
sample = exponential(beta, n)
print(sample)
运行该示例将打印从定义的分布中随机采样的 10 个数字。
[ 3.32742946 39.10165624 41.86856606 85.0030387 28.18425491
68.20434637 106.34826579 19.63637359 17.13805423 15.91135881]
我们可以使用指数函数定义指数分布,然后计算矩、PDF、CDF 等属性。
下面的例子定义了一个介于 50 和 70 之间的观测值范围,计算了每个观测值的概率和累积概率,并绘制了结果图。
# pdf and cdf for an exponential distribution
from scipy.stats import expon
from matplotlib import pyplot
# define distribution parameter
beta = 50
# create distribution
dist = expon(beta)
# plot pdf
values = [value for value in range(50, 70)]
probabilities = [dist.pdf(value) for value in values]
pyplot.plot(values, probabilities)
pyplot.show()
# plot cdf
cprobs = [dist.cdf(value) for value in values]
pyplot.plot(values, cprobs)
pyplot.show()
运行该示例首先创建结果与概率的折线图,显示熟悉的指数概率分布形状。
事件对概率或指数分布的概率密度函数的线图
接下来,计算每个结果的累积概率,并绘制成线形图,表明在值 55 之后,将观察到几乎 100%的期望值。
事件与指数分布的累积概率或累积密度函数的线图
一个重要的相关分布是双指数分布,也称为拉普拉斯分布。
帕累托分布
一个帕累托分布以维尔弗雷多·帕累托命名,可以称为一个幂律分布。
它还与帕累托原则(或 80/20 规则)有关,这是一种遵循帕累托分布的连续随机变量的启发式方法,其中 80%的事件被 20%的结果范围覆盖,例如,大多数事件仅来自连续变量范围的 20%。
帕累托原则只是一个特定帕累托分布的启发,特别是帕累托第二类分布,这可能是最有趣的,我们将集中讨论。
具有帕累托分布事件的域的一些示例包括:
- 一个国家家庭的收入。
- 图书销售总额。
- 运动队队员的得分。
可以使用一个参数定义分布:
- 形状(α):概率下降的陡度。
形状参数的值通常很小,例如在 1 和 3 之间,当 alpha 设置为 1.161 时给出了 Pareto 原则。
我们可以定义一个形状为 1.1 的分布,并从这个分布中抽取随机数。我们可以使用 pareto() NumPy 函数来实现。
# sample a pareto distribution
from numpy.random import pareto
# define the distribution
alpha = 1.1
n = 10
# generate the sample
sample = pareto(alpha, n)
print(sample)
运行该示例将打印从定义的分布中随机采样的 10 个数字。
[0.5049704 0.0140647 2.13105224 3.10991217 2.87575892 1.06602639
0.22776379 0.37405415 0.96618778 3.94789299]
我们可以使用 pareto() SciPy 函数定义一个 Pareto 分布,然后计算属性,比如矩、PDF、CDF 等等。
下面的例子定义了一个介于 1 到 10 之间的观测值范围,计算了每个观测值的概率和累积概率,并绘制了结果图。
# pdf and cdf for a pareto distribution
from scipy.stats import pareto
from matplotlib import pyplot
# define distribution parameter
alpha = 1.5
# create distribution
dist = pareto(alpha)
# plot pdf
values = [value/10.0 for value in range(10, 100)]
probabilities = [dist.pdf(value) for value in values]
pyplot.plot(values, probabilities)
pyplot.show()
# plot cdf
cprobs = [dist.cdf(value) for value in values]
pyplot.plot(values, cprobs)
pyplot.show()
运行该示例首先创建结果与概率的折线图,显示熟悉的帕累托概率分布形状。
事件与概率或帕累托分布的概率密度函数的线图
接下来,计算每个结果的累积概率,并绘制成线形图,显示上升幅度小于上一节中看到的指数分布。
事件的线图与累积概率或帕累托分布的累积密度函数
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
书
应用程序接口
文章
摘要
在本教程中,您发现了机器学习中使用的连续概率分布。
具体来说,您了解到:
- 连续随机变量的结果概率可以用连续概率分布来概括。
- 如何从常见的连续概率分布中参数化、定义和随机采样。
- 如何为常见的连续概率分布创建概率密度和累积密度图?
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
机器学习交叉熵的温和介绍
最后更新于 2020 年 12 月 22 日
交叉熵通常在机器学习中用作损失函数。
交叉熵是信息论领域的一个度量,建立在熵的基础上,一般计算两个概率分布的差值。它与计算两个概率分布之间相对熵的 KL 散度密切相关但又不同,而交叉熵可以认为是计算分布之间的总熵。
交叉熵也与逻辑损失有关,经常被混淆,称为对数损失。虽然这两种度量来自不同的来源,但当用作分类模型的损失函数时,两种度量计算的数量相同,可以互换使用。
在本教程中,您将发现机器学习的交叉熵。
完成本教程后,您将知道:
- 如何从零开始使用标准机器学习库计算交叉熵?
- 交叉熵可用作优化分类模型(如逻辑回归和人工神经网络)时的损失函数。
- 交叉熵不同于 KL 散度,但可以使用 KL 散度计算,并且不同于对数损失,但在用作损失函数时计算相同的量。
用我的新书机器学习概率启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
- 更新 2019 年 10 月:给出了相同分布的交叉熵的例子,并更新了这种情况的描述(感谢罗恩·U)。增加了一个计算已知类标签熵的例子。
- 2019 年 11 月更新:结构改进,增加了更多熵的解释。增加了对预测类概率的直觉。
- 2020 年 12 月更新:调整了信息和熵的介绍,使之更加清晰。
机器学习交叉熵简介 图片由杰罗姆·邦提供,版权所有。
教程概述
本教程分为五个部分;它们是:
- 什么是交叉熵?
- 交叉熵与 KL 散度
- 如何计算交叉熵
- 两种离散概率分布
- 计算分布之间的交叉熵
- 计算分布与自身之间的交叉熵
- 用 KL 散度计算交叉熵
- 作为损失函数的交叉熵
- 计算类别标签的熵
- 计算类别标签和概率之间的交叉熵
- 使用 Keras 计算交叉熵
- 预测概率的交叉熵直觉
- 交叉熵与对数损失
- 对数损失是负的对数可能性
- 对数损失和交叉熵计算同样的事情
什么是交叉熵?
交叉熵是对给定随机变量或事件集的两个概率分布之间差异的度量。
您可能还记得信息量化了编码和传输事件所需的位数。低概率事件信息多,高概率事件信息少。
在信息论中,我们喜欢描述一个事件的“惊喜”。一个事件越不可能越令人惊讶,这意味着它包含了更多的信息。
- 低概率事件 ( 惊喜):更多信息。
- 更高概率事件 ( 不出所料):信息更少。
给定事件 P(x) 的概率,可以为事件 x 计算信息 h(x) 如下:
- h(x)=-对数(P(x))
熵是从概率分布中传输随机选择的事件所需的位数。偏斜分布的熵较低,而事件概率相等的分布熵较大。
一个偏斜的概率分布有较少的“惊喜”,反过来低熵,因为可能的事件占主导地位。平衡分布更令人惊讶,反过来也有更高的熵,因为事件同样可能发生。
- 偏斜概率分布 ( 不出所料):低熵。
- 均衡概率分布 ( 惊人):高熵。
熵 H(x) 可以用一组 X 离散状态中的 x 离散状态及其概率 P(x) 来计算,如下所示:
- h(X)=–X 中 X 的总和 P(x) * log(P(x))
如果您想了解更多关于计算事件信息和分布熵的信息,请参阅本教程:
交叉熵建立在信息论中熵的概念之上,计算表示或传输一个分布的平均事件相对于另一个分布所需的比特数。
…交叉熵是当我们使用模型 q 时,对来自分布为 p 的源的数据进行编码所需的平均位数…
—第 57 页,机器学习:概率视角,2012。
这个定义的直觉来自于如果我们考虑一个目标或潜在的概率分布 P 和目标分布 Q 的近似值,那么 Q 来自 P 的交叉熵就是用 Q 而不是 P 来表示一个事件的附加比特数
两个概率分布之间的交叉熵,如 P 中的 Q,可以正式表述为:
- 高(P,Q)
其中 H()是交叉熵函数,P 可能是目标分布,Q 是目标分布的近似值。
交叉熵可以使用事件概率 P 和 Q 来计算,如下所示:
- H(P,Q)=–X 中 X 的总和 P(x) * log(Q(x))
其中 P(x)是事件 x 在 P 中的概率,Q(x)是事件 x 在 Q 中的概率,log 是以 2 为底的对数,意味着结果以比特为单位。如果用以 e 为底的对数或自然对数来代替,结果将有称为 nats 的单位。
这种计算是针对离散概率分布的,尽管类似的计算可以用于连续概率分布,使用事件的积分而不是总和。
如果两个概率分布相同,结果将是以比特为单位测量的正数,并等于分布的熵。
注:这个符号看起来很像 P 和 q 之间的联合概率,或者更具体地说是联合熵,这是误导,因为我们是在用交叉熵对概率分布之间的差异进行评分。然而,联合熵是一个不同的概念,它使用相同的符号,而是计算两个(或更多)随机变量的不确定性。
交叉熵与 KL 散度
交叉熵不是 KL 散度。
交叉熵与散度度量有关,例如库勒贝克-莱布勒,或 KL,散度,它量化了一个分布与另一个分布的差异。
具体来说,KL 散度度量了一个与交叉熵非常相似的量。它测量用 Q 而不是 P 表示一条消息所需的平均额外位数,而不是总位数。
换句话说,KL 散度是编码数据所需的额外比特的平均数量,因为我们使用分布 q 来编码数据,而不是真正的分布 p。
—第 58 页,机器学习:概率视角,2012。
因此,KL 散度通常被称为“相对熵”
- 交叉熵:从 Q 而不是 p 表示事件的平均总位数
- 相对熵 ( KL 散度):从 Q 而不是 p 表示事件的平均额外位数
KL 散度可以计算为以 P 为倍数的每个事件的概率的负和,乘以事件在 Q 中的概率对事件在 P 中的概率的对数。通常,对数基数为-2,因此结果以比特为单位进行测量。
- KL(P | | Q)=–X 中 X 的和 P(x) * log(Q(x) / P(x))
总和中的值是给定事件的散度。
因此,我们可以通过将分布的熵加上由 KL 散度计算的附加熵来计算交叉熵。考虑到两种计算的定义,这是直观的;例如:
- H(P,Q) = H(P) + KL(P || Q)
其中 H(P,Q)是 Q 与 P 的交叉熵,H(P)是 P 的熵,KL(P || Q)是 Q 与 P 的散度。
对于概率分布,熵可以计算为每个事件概率的负和乘以事件概率的对数,其中对数以 2 为基数,以确保结果以位为单位。
- h(P)=-X P(X)* log(P(X))上的和 X
像 KL 散度一样,交叉熵也不是对称的,这意味着:
- H(P,Q)!= H(Q,P)
正如我们将在后面看到的,当交叉熵和 KL 散度用作优化分类预测模型的损失函数时,它们计算相同的量。正是在这种背景下,你有时可能会看到交叉熵和 KL 散度是相同的。
有关 KL 散度的更多细节,请参见教程:
如何计算交叉熵
在这一节中,我们将用一个小例子来具体计算交叉熵。
两种离散概率分布
考虑一个随机变量,它有三个不同颜色的离散事件:红色、绿色和蓝色。
对于这个变量,我们可能有两种不同的概率分布;例如:
...
# define distributions
events = ['red', 'green', 'blue']
p = [0.10, 0.40, 0.50]
q = [0.80, 0.15, 0.05]
我们可以绘制这些概率的条形图,将它们直接作为概率直方图进行比较。
下面列出了完整的示例。
# plot of distributions
from matplotlib import pyplot
# define distributions
events = ['red', 'green', 'blue']
p = [0.10, 0.40, 0.50]
q = [0.80, 0.15, 0.05]
print('P=%.3f Q=%.3f' % (sum(p), sum(q)))
# plot first distribution
pyplot.subplot(2,1,1)
pyplot.bar(events, p)
# plot second distribution
pyplot.subplot(2,1,2)
pyplot.bar(events, q)
# show the plot
pyplot.show()
运行该示例会为每个概率分布创建一个直方图,从而可以直接比较每个事件的概率。
我们可以看到,分布确实是不同的。
同一随机变量两种不同概率分布的直方图
计算分布之间的交叉熵
接下来,我们可以开发一个函数来计算两个分布之间的交叉熵。
我们将使用 log base-2 来确保结果以位为单位。
# calculate cross entropy
def cross_entropy(p, q):
return -sum([p[i]*log2(q[i]) for i in range(len(p))])
然后我们可以用这个函数从 Q 计算 P 的交叉熵,以及反过来,从 P 计算 Q。
...
# calculate cross entropy H(P, Q)
ce_pq = cross_entropy(p, q)
print('H(P, Q): %.3f bits' % ce_pq)
# calculate cross entropy H(Q, P)
ce_qp = cross_entropy(q, p)
print('H(Q, P): %.3f bits' % ce_qp)
将这些结合在一起,完整的示例如下所示。
# example of calculating cross entropy
from math import log2
# calculate cross entropy
def cross_entropy(p, q):
return -sum([p[i]*log2(q[i]) for i in range(len(p))])
# define data
p = [0.10, 0.40, 0.50]
q = [0.80, 0.15, 0.05]
# calculate cross entropy H(P, Q)
ce_pq = cross_entropy(p, q)
print('H(P, Q): %.3f bits' % ce_pq)
# calculate cross entropy H(Q, P)
ce_qp = cross_entropy(q, p)
print('H(Q, P): %.3f bits' % ce_qp)
运行该示例时,首先从 P 计算 Q 的交叉熵,刚好超过 3 位,然后从 Q 计算 P,刚好低于 3 位。
H(P, Q): 3.288 bits
H(Q, P): 2.906 bits
计算分布与自身之间的交叉熵
如果两个概率分布相同,那么它们之间的交叉熵就是分布的熵。
我们可以通过计算 P 对 P 和 Q 对 Q 的交叉熵来证明这一点
下面列出了完整的示例。
# example of calculating cross entropy for identical distributions
from math import log2
# calculate cross entropy
def cross_entropy(p, q):
return -sum([p[i]*log2(q[i]) for i in range(len(p))])
# define data
p = [0.10, 0.40, 0.50]
q = [0.80, 0.15, 0.05]
# calculate cross entropy H(P, P)
ce_pp = cross_entropy(p, p)
print('H(P, P): %.3f bits' % ce_pp)
# calculate cross entropy H(Q, Q)
ce_qq = cross_entropy(q, q)
print('H(Q, Q): %.3f bits' % ce_qq)
运行该示例首先计算 Q 对 Q 的交叉熵,它被计算为 Q 的熵,以及 P 对 P,它被计算为 P 的熵
H(P, P): 1.361 bits
H(Q, Q): 0.884 bits
用 KL 散度计算交叉熵
我们也可以使用 KL 散度来计算交叉熵。
用 KL 散度计算的交叉熵应该是相同的,并且计算分布之间的 KL 散度以查看相对熵或所需的额外比特而不是由交叉熵计算的总比特可能是有趣的。
首先,我们可以定义一个函数,使用 log base-2 计算分布之间的 KL 散度,以确保结果也是以位为单位的。
# calculate the kl divergence KL(P || Q)
def kl_divergence(p, q):
return sum(p[i] * log2(p[i]/q[i]) for i in range(len(p)))
接下来,我们可以定义一个函数来计算给定概率分布的熵。
# calculate entropy H(P)
def entropy(p):
return -sum([p[i] * log2(p[i]) for i in range(len(p))])
最后,我们可以使用*熵()和KL _ 散度()*函数计算交叉熵。
# calculate cross entropy H(P, Q)
def cross_entropy(p, q):
return entropy(p) + kl_divergence(p, q)
为了简单起见,我们可以将 H(P,Q)的交叉熵与 KL 散度 KL(P || Q)和熵 H(P)进行比较。
下面列出了完整的示例。
# example of calculating cross entropy with kl divergence
from math import log2
# calculate the kl divergence KL(P || Q)
def kl_divergence(p, q):
return sum(p[i] * log2(p[i]/q[i]) for i in range(len(p)))
# calculate entropy H(P)
def entropy(p):
return -sum([p[i] * log2(p[i]) for i in range(len(p))])
# calculate cross entropy H(P, Q)
def cross_entropy(p, q):
return entropy(p) + kl_divergence(p, q)
# define data
p = [0.10, 0.40, 0.50]
q = [0.80, 0.15, 0.05]
# calculate H(P)
en_p = entropy(p)
print('H(P): %.3f bits' % en_p)
# calculate kl divergence KL(P || Q)
kl_pq = kl_divergence(p, q)
print('KL(P || Q): %.3f bits' % kl_pq)
# calculate cross entropy H(P, Q)
ce_pq = cross_entropy(p, q)
print('H(P, Q): %.3f bits' % ce_pq)
运行该示例,我们可以看到 3.288 位的交叉熵得分由 P 1.361 的熵和通过 KL 散度计算的额外的 1.927 位组成。
这是一个有用的例子,清楚地说明了所有三个计算之间的关系。
H(P): 1.361 bits
KL(P || Q): 1.927 bits
H(P, Q): 3.288 bits
作为损失函数的交叉熵
在优化分类模型时,交叉熵被广泛用作损失函数。
您可能会遇到两个例子,包括逻辑回归算法(线性分类算法)和可用于分类任务的人工神经网络。
…在分类问题中使用交叉熵误差函数而不是平方和,可以加快训练速度并提高泛化能力。
—第 235 页,模式识别与机器学习,2006。
分类问题是那些涉及一个或多个输入变量和类标签预测的问题。
对于输出变量只有两个标签的分类任务被称为二进制分类问题,而那些有两个以上标签的问题被称为分类或多类分类问题。
- 二进制分类:预测给定示例的两个类别标签之一的任务。
- 多类分类:预测给定示例的两个以上类标签之一的任务。
我们可以看到交叉熵的思想对于优化分类模型可能是有用的。
每个示例都有一个已知的类标签,概率为 1.0,所有其他标签的概率为 0.0。模型可以估计一个例子属于每个类别标签的概率。交叉熵然后可以用来计算两个概率分布之间的差异。
因此,我们可以将一个例子的分类映射到具有如下概率分布的随机变量的概念上:
- 随机变量:我们需要一个预测类标签的例子。
- 事件:每个可以预测的类标签。
在分类任务中,我们知道一个输入的目标概率分布 P 作为类标签 0 或 1,分别解释为“不可能”或“确定”的概率。这些概率一点也不令人惊讶,因此它们没有信息量或零熵。
我们的模型试图近似目标概率分布 q。
在分类语言中,这些是实际概率和预测概率,或 y 和 yhat 。
- 期望概率 ( y ):数据集中某个示例的每个类标签的已知概率(P)。
- 预测概率 ( yhat ):每个类标注一个模型预测的例子的概率(Q)。
因此,我们可以使用上述交叉熵计算来估计单个预测的交叉熵;比如说。
- H(P,Q)=–X 中 X 的总和 P(x) * log(Q(x))
其中 X 中的每个 x 是可以分配给该示例的类别标签, P(x) 对于已知标签为 1,对于所有其他标签为 0。
二分类任务中单个示例的交叉熵可以通过如下展开求和操作来表示:
- H(P,Q)=–(P(0 级)*对数(Q(0 级))+P(1 级)*对数(Q(1 级))
你可能会在教科书中看到这种计算交叉熵的形式。
如果只有两个类别标签,概率建模为正类别标签的伯努利分布。这意味着类别 1 的概率由模型直接预测,而类别 0 的概率给出为 1 减去预测概率,例如:
- 预测 P(0 级)= 1–yhat
- 预测 P(1 级) = yhat
当计算分类任务的交叉熵时,使用以 e 为底的对数或自然对数。这意味着单位是 nats,而不是位。
我们通常对最小化整个训练数据集中模型的交叉熵感兴趣。这是通过计算所有训练示例的平均交叉熵来计算的。
计算类别标签的熵
回想一下,当两个分布相同时,它们之间的交叉熵等于概率分布的熵。
为分类任务准备数据时,使用值 0 和 1 对类标签进行编码。
例如,如果一个分类问题有三类,一个例子有第一类的标签,那么概率分布将是[1,0,0]。如果一个例子有第二类的标签,它将有两个事件的概率分布为[0,1,0]。这叫做一个热编码。
这个概率分布没有信息,因为结果是确定的。我们知道这门课。因此,这个变量的熵为零。
这是一个重要的概念,我们可以用一个成功的例子来证明。
假设有一个 3 类的分类问题,我们有一个属于每个类的例子。我们可以将每个示例表示为离散的概率分布,对于该示例所属的类,概率为 1.0,对于所有其他类,概率为 0.0。
我们可以计算出“事件中每个“变量”的概率分布熵。
下面列出了完整的示例。
# entropy of examples from a classification task with 3 classes
from math import log2
from numpy import asarray
# calculate entropy
def entropy(p):
return -sum([p[i] * log2(p[i]) for i in range(len(p))])
# class 1
p = asarray([1,0,0]) + 1e-15
print(entropy(p))
# class 2
p = asarray([0,1,0]) + 1e-15
print(entropy(p))
# class 3
p = asarray([0,0,1]) + 1e-15
print(entropy(p))
运行该示例计算每个随机变量的熵。
我们可以看到,在每种情况下,熵都是 0.0(实际上是一个非常接近于零的数字)。
请注意,我们必须在 0.0 值上添加一个非常小的值,以避免 log() 爆炸,因为我们无法计算 0.0 的 log。
9.805612959471341e-14
9.805612959471341e-14
9.805612959471341e-14
因此,已知类别标签的熵总是 0.0。
这意味着对于一个类标签具有相同概率分布的两个分布(真实的和预测的)的交叉熵也将总是 0.0。
回想一下,在训练数据集上使用交叉熵评估模型时,我们对数据集中所有示例的交叉熵进行平均。
因此,当训练模型时交叉熵为 0.0 表明预测的类概率与训练数据集中的概率相同,例如零损失。
我们可以很容易地将 KL 散度最小化为损失函数,而不是交叉熵。
回想一下,KL 散度是传输一个变量相对于另一个变量所需的额外比特。它是没有类标签熵的交叉熵,我们知道它无论如何都是零。
因此,最小化分类任务的 KL 散度和交叉熵是相同的。
最小化这种 KL 散度正好对应于最小化分布之间的交叉熵。
—第 132 页,深度学习,2016。
在实践中,交叉熵损失为 0.0 通常表明模型过度训练了训练数据集,但这是另一回事。
计算类别标签和概率之间的交叉熵
使用交叉熵进行分类通常会根据类的数量给出不同的具体名称,反映了分类任务的名称;例如:
- 二元交叉熵:交叉熵作为二分类任务的损失函数。
- 分类交叉熵:交叉熵作为多类分类任务的损失函数。
我们可以用一个具体的例子来说明交叉熵作为损失函数的用途。
考虑一个包含以下 10 个实际类标签(P)和预测类标签(Q)的两类分类任务。
...
# define classification data
p = [1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
q = [0.8, 0.9, 0.9, 0.6, 0.8, 0.1, 0.4, 0.2, 0.1, 0.3]
我们可以枚举这些概率,并使用上一节中开发的交叉熵函数计算每个概率的交叉熵,使用 log() (自然对数)代替 log2() 。
# calculate cross entropy
def cross_entropy(p, q):
return -sum([p[i]*log(q[i]) for i in range(len(p))])
对于每个实际和预测的概率,我们必须将预测转换为每个事件的概率分布,在这种情况下,类别{0,1}为 1 减去类别 0 的概率和类别 1 的概率。
然后,我们可以计算交叉熵,并对所有示例重复该过程。
...
# calculate cross entropy for each example
results = list()
for i in range(len(p)):
# create the distribution for each event {0, 1}
expected = [1.0 - p[i], p[i]]
predicted = [1.0 - q[i], q[i]]
# calculate cross entropy for the two events
ce = cross_entropy(expected, predicted)
print('>[y=%.1f, yhat=%.1f] ce: %.3f nats' % (p[i], q[i], ce))
results.append(ce)
最后,我们可以计算整个数据集的平均交叉熵,并将其报告为数据集上模型的交叉熵损失。
...
# calculate the average cross entropy
mean_ce = mean(results)
print('Average Cross Entropy: %.3f nats' % mean_ce)
将这些结合在一起,完整的示例如下所示。
# calculate cross entropy for classification problem
from math import log
from numpy import mean
# calculate cross entropy
def cross_entropy(p, q):
return -sum([p[i]*log(q[i]) for i in range(len(p))])
# define classification data
p = [1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
q = [0.8, 0.9, 0.9, 0.6, 0.8, 0.1, 0.4, 0.2, 0.1, 0.3]
# calculate cross entropy for each example
results = list()
for i in range(len(p)):
# create the distribution for each event {0, 1}
expected = [1.0 - p[i], p[i]]
predicted = [1.0 - q[i], q[i]]
# calculate cross entropy for the two events
ce = cross_entropy(expected, predicted)
print('>[y=%.1f, yhat=%.1f] ce: %.3f nats' % (p[i], q[i], ce))
results.append(ce)
# calculate the average cross entropy
mean_ce = mean(results)
print('Average Cross Entropy: %.3f nats' % mean_ce)
运行该示例会打印每个示例的实际概率和预测概率以及 nats 中的交叉熵。
在本例中,所有示例的最终平均交叉熵损失为 0.247 纳特。
>[y=1.0, yhat=0.8] ce: 0.223 nats
>[y=1.0, yhat=0.9] ce: 0.105 nats
>[y=1.0, yhat=0.9] ce: 0.105 nats
>[y=1.0, yhat=0.6] ce: 0.511 nats
>[y=1.0, yhat=0.8] ce: 0.223 nats
>[y=0.0, yhat=0.1] ce: 0.105 nats
>[y=0.0, yhat=0.4] ce: 0.511 nats
>[y=0.0, yhat=0.2] ce: 0.223 nats
>[y=0.0, yhat=0.1] ce: 0.105 nats
>[y=0.0, yhat=0.3] ce: 0.357 nats
Average Cross Entropy: 0.247 nats
这是在交叉熵损失函数下优化逻辑回归模型或神经网络模型时计算交叉熵损失的方式。
使用 Keras 计算交叉熵
我们可以通过使用来自 Keras 深度学习 API 的*二元 _ 交叉熵()*函数来为我们的小数据集计算交叉熵损失,从而确认相同的计算。
下面列出了完整的示例。
注意:本例假设您安装了 Keras 库(例如 2.3 版或更高版本),并配置了后端库,例如TensorFlow(2.0 版或更高版本)。如果没有,您可以跳过运行这个示例。
# calculate cross entropy with keras
from numpy import asarray
from keras import backend
from keras.losses import binary_crossentropy
# prepare classification data
p = asarray([1, 1, 1, 1, 1, 0, 0, 0, 0, 0])
q = asarray([0.8, 0.9, 0.9, 0.6, 0.8, 0.1, 0.4, 0.2, 0.1, 0.3])
# convert to keras variables
y_true = backend.variable(p)
y_pred = backend.variable(q)
# calculate the average cross-entropy
mean_ce = backend.eval(binary_crossentropy(y_true, y_pred))
print('Average Cross Entropy: %.3f nats' % mean_ce)
运行该示例,我们可以看到报告了相同的平均交叉熵损失 0.247 nats。
这证实了交叉熵的正确人工计算。
Average Cross Entropy: 0.247 nats
预测概率的交叉熵直觉
我们可以进一步发展预测类概率的交叉熵的直觉。
例如,假设平均交叉熵损失为 0.0 是一个完美的模型,那么大于零的平均交叉熵值到底意味着什么?
我们可以探讨这个问题没有一个二进制分类问题,其中类标签为 0 和 1。这是一个离散的概率分布,有两个事件,一个事件有一定的概率,另一个事件有不可能的概率。
然后,我们可以计算从目标分布的完美匹配过渡到完全相反的概率分布的不同“”预测的”概率分布的交叉熵。
我们预计,随着预测的概率分布进一步偏离目标分布,计算的交叉熵将增加。
下面的示例实现了这一点,并绘制了预测概率分布的交叉熵结果与两个事件的目标[0,1]的比较,就像我们在二分类任务中看到的交叉熵一样。
# cross-entropy for predicted probability distribution vs label
from math import log
from matplotlib import pyplot
# calculate cross-entropy
def cross_entropy(p, q, ets=1e-15):
return -sum([p[i]*log(q[i]+ets) for i in range(len(p))])
# define the target distribution for two events
target = [0.0, 1.0]
# define probabilities for the first event
probs = [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0]
# create probability distributions for the two events
dists = [[1.0 - p, p] for p in probs]
# calculate cross-entropy for each distribution
ents = [cross_entropy(target, d) for d in dists]
# plot probability distribution vs cross-entropy
pyplot.plot([1-p for p in probs], ents, marker='.')
pyplot.title('Probability Distribution vs Cross-Entropy')
pyplot.xticks([1-p for p in probs], ['[%.1f,%.1f]'%(d[0],d[1]) for d in dists], rotation=70)
pyplot.subplots_adjust(bottom=0.2)
pyplot.xlabel('Probability Distribution')
pyplot.ylabel('Cross-Entropy (nats)')
pyplot.show()
运行该示例计算每个概率分布的交叉熵得分,然后将结果绘制为线形图。
我们可以看到,正如预期的那样,当预测的概率分布与目标分布匹配时,交叉熵从 0.0(最左侧点)开始,然后随着预测的概率分布发散而稳定增加。
当预测的概率分布与目标分布完全相反时,即[1,0]与[0,1]的目标相比,我们也可以看到交叉熵的戏剧性飞跃。
二分类任务的概率分布与交叉熵的线图
我们不会有一个模型来预测二分类任务中所有情况的完全相反的概率分布。
因此,我们可以删除这个案例,重新计算情节。
下面列出了代码的更新版本。
# cross-entropy for predicted probability distribution vs label
from math import log
from matplotlib import pyplot
# calculate cross-entropy
def cross_entropy(p, q, ets=1e-15):
return -sum([p[i]*log(q[i]+ets) for i in range(len(p))])
# define the target distribution for two events
target = [0.0, 1.0]
# define probabilities for the first event
probs = [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1]
# create probability distributions for the two events
dists = [[1.0 - p, p] for p in probs]
# calculate cross-entropy for each distribution
ents = [cross_entropy(target, d) for d in dists]
# plot probability distribution vs cross-entropy
pyplot.plot([1-p for p in probs], ents, marker='.')
pyplot.title('Probability Distribution vs Cross-Entropy')
pyplot.xticks([1-p for p in probs], ['[%.1f,%.1f]'%(d[0],d[1]) for d in dists], rotation=70)
pyplot.subplots_adjust(bottom=0.2)
pyplot.xlabel('Probability Distribution')
pyplot.ylabel('Cross-Entropy (nats)')
pyplot.show()
运行该示例可以更好地了解概率分布中的散度和计算出的交叉熵之间的关系。
我们可以看到一个超线性关系,其中预测的概率分布偏离目标越多,交叉熵增加越大。
去除极端情况下二分类任务的概率分布与交叉熵的线图
像这样的图可以用作解释二元类别数据集模型的平均交叉熵报告的指南。
例如,您可以使用这些交叉熵值来解释 Keras 为二进制分类任务的神经网络模型或 Sklearn 中使用对数损失度量评估的二进制分类模型报告的平均交叉熵。
你可以用它来回答一般的问题:
什么是好的交叉熵得分?
如果你在 nats 工作(你通常都是),并且你得到的平均交叉熵小于 0.2,你就有了一个好的开始,小于 0.1 或 0.05 更好。
另一方面,如果你得到的平均交叉熵大于 0.2 或 0.3,你可能会有所改善,如果你得到的平均交叉熵大于 1.0,那么有些事情正在发生,你对数据集中的许多例子做出了糟糕的概率预测。
我们可以将平均交叉熵的这些直觉总结如下:
- 交叉熵= 0.00 :完美概率。
- 交叉熵< 0.02 :大概率。
- 交叉熵< 0.05 :在正轨上。
- 交叉熵< 0.20 :好。
- 交叉熵> 0.30 :不大。
- 交叉熵> 1.00 :可怕。
- 交叉熵> 2.00 有东西坏了。
当从逻辑回归模型或人工神经网络模型中解释交叉熵(对数损失)时,这个列表将提供有用的指导。
您还可以计算每个类的独立平均交叉熵得分,并帮助梳理出您所建模的哪些类具有良好的概率,以及哪些类可能会被搞砸。
交叉熵与对数损失
交叉熵不是对数损失,但是当用作分类问题的损失函数时,它们计算相同的量。
对数损失是负的对数可能性
Logistic 损失是指常用于优化一个 Logistic 回归模型的损失函数。
它也可以被称为对数损失(这是令人困惑的)或简单的对数损失。
许多模型是在一个叫做最大似然估计的概率框架下优化的,该框架涉及到寻找一组最能解释观测数据的参数。
这包括选择一个似然函数,定义一组观测值(数据)被赋予模型参数的可能性。当使用对数似然函数时(这是常见的),它通常被称为优化模型的对数似然。因为在实践中,最小化函数比最大化函数更常见,所以对数似然函数通过在前面添加负号来反转。这将其转换为负对数似然函数,简称 NLL。
在伯努利概率分布函数(两类)的最大似然估计框架下推导对数似然函数时,计算结果为:
- 负对数似然(P,Q) = -(P(类 0) *对数(Q(类 0)) + P(类 1) *对数(Q(类 1))
这个量可以通过计算似然函数的对数的平均值在所有训练例子上求平均值。
二分类问题的负对数似然通常被简称为“对数损失”,作为逻辑回归的损失函数。
- 对数损失=负对数似然,在伯努利概率分布下
我们可以看到负对数似然与伯努利概率分布函数(两个事件或类别)的交叉熵计算相同。事实上,多欧拉分布(多类分类)的负对数似然性也与交叉熵的计算相匹配。
有关日志丢失和负日志可能性的更多信息,请参见教程:
对数损失和交叉熵计算同样的事情
对于分类问题,“对数损失”、“交叉熵”和“负对数似然”可互换使用。
更一般地,术语“交叉熵”和“负对数似然”在分类模型的损失函数的上下文中可互换使用。
逻辑回归的负对数似然由[…]给出,这也称为交叉熵误差函数。
—第 246 页,机器学习:概率视角,2012。
因此,计算对数损失将给出与计算伯努利概率分布的交叉熵相同的量。我们可以通过使用 Sklearn API 中的 log_loss()函数计算 log loss 来确认这一点。
计算上一节中同一组实际和预测概率的平均测井损失应给出与计算平均交叉熵相同的结果。
下面列出了完整的示例。
# calculate log loss for classification problem with Sklearn
from sklearn.metrics import log_loss
from numpy import asarray
# define classification data
p = [1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
q = [0.8, 0.9, 0.9, 0.6, 0.8, 0.1, 0.4, 0.2, 0.1, 0.3]
# define data as expected, e.g. probability for each event {0, 1}
y_true = asarray([[1-v, v] for v in p])
y_pred = asarray([[1-v, v] for v in q])
# calculate the average log loss
ll = log_loss(y_true, y_pred)
print('Average Log Loss: %.3f' % ll)
运行该示例给出了 0.247 个日志丢失的预期结果,当使用平均交叉熵计算时,该结果与 0.247 个 nats 匹配。
Average Log Loss: 0.247
这并不意味着对数损失计算交叉熵或交叉熵计算对数损失。
相反,它们是不同的量,来自不同的研究领域,在为分类任务计算损失函数的条件下,导致等价的计算和结果。具体而言,交叉熵损失函数相当于伯努利或多努里概率分布下的最大似然函数。
这证明了最大似然估计的研究和离散概率分布的信息论之间的联系。
它不限于离散的概率分布,这个事实让许多第一次听到的从业者感到惊讶。
具体而言,在最大似然估计框架下优化的线性回归假设目标变量的高斯连续概率分布,并且涉及最小化均方误差函数。这相当于高斯概率分布随机变量的交叉熵。
由负对数似然构成的任何损失都是训练集定义的经验分布和模型定义的概率分布之间的交叉熵。例如,均方误差是经验分布和高斯模型之间的交叉熵。
—第 132 页,深度学习,2016。
这有点令人瞠目结舌,来源于连续随机变量的微分熵领域。
这意味着,如果你计算覆盖相同事件的两个高斯随机变量之间的均方误差(具有相同的均值和标准差),那么你就是在计算变量之间的交叉熵。
这也意味着,如果你使用均方误差损失来优化回归问题的神经网络模型,你实际上是在使用交叉熵损失。
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
教程
书
应用程序接口
文章
摘要
在本教程中,您发现了机器学习的交叉熵。
具体来说,您了解到:
- 如何从零开始使用标准机器学习库计算交叉熵?
- 交叉熵可用作优化分类模型(如逻辑回归和人工神经网络)时的损失函数。
- 交叉熵不同于 KL 散度,但可以使用 KL 散度计算,并且不同于对数损失,但在用作损失函数时计算相同的量。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。