python - 计算矩阵行和向量行之间的 KL 散度
问题描述
我有一个矩阵(numpy 2d 数组),其中每一行都是有效的概率分布。我有另一个向量(numpy 1d 数组),也是一个概率分布。我需要计算矩阵的每一行和向量之间的 KL 散度。是否可以在不使用 for 循环的情况下做到这一点?
这个问题问的是同样的事情,但没有一个答案能解决我的问题。其中之一建议使用我想避免的 for 循环,因为我有大量数据。另一个答案在 tensorflow 中提供了一个解决方案,但我想要 numpy 数组。
scipy.stats.entropy计算 2 个向量之间的 KL 散度,但是当其中一个是矩阵时,我不知道如何使用它。
解决方案
实际上,该函数scipy.stats.entropy
可以进行矢量化计算,但是您必须适当地重塑参数才能使其工作。当输入是二维数组时,entropy
期望列保存概率向量。在p
是二维和q
一维的情况下,必须添加一个平凡的维度q
以使参数与广播兼容。
这是一个例子。一、进口:
In [10]: import numpy as np
In [11]: from scipy.stats import entropy
创建一个二维p
,其行是概率向量,以及一个一维概率向量q
:
In [12]: np.random.seed(8675309)
In [13]: p = np.random.rand(3, 5)
In [14]: p /= p.sum(axis=1, keepdims=True)
In [15]: q = np.random.rand(5)
In [16]: q /= q.sum()
In [17]: p
Out[17]:
array([[0.32085531, 0.29660176, 0.14113073, 0.07988999, 0.1615222 ],
[0.05870513, 0.15367858, 0.29585406, 0.01298657, 0.47877566],
[0.1914319 , 0.29324935, 0.1093297 , 0.17710131, 0.22888774]])
In [18]: q
Out[18]: array([0.06804561, 0.35392387, 0.29008139, 0.04580467, 0.24214446])
为了与矢量化结果进行比较,这里是使用 Python 循环计算的结果。
In [19]: [entropy(t, q) for t in p]
Out[19]: [0.32253909299531597, 0.17897138916539493, 0.2627905326857023]
为了进行entropy
向量化计算,第一个参数的列必须是概率向量,所以我们将转置p
. 然后,为了q
与 兼容p.T
,我们将其重塑为形状为 (5, 1) 的二维数组(即它包含一列):
In [20]: entropy(p.T, q.reshape(-1, 1))
Out[20]: array([0.32253909, 0.17897139, 0.26279053])
注意:用作第二个参数很诱人q.T
,但这不起作用。在 NumPy 中,转置操作只交换现有维度的长度——它从不创建新维度。所以一维数组的转置就是它本身。即,q.T
与 的形状相同q
。
此答案的旧版本如下...
您可以使用scipy.special.kl_div
或scipy.special.rel_entr
来执行此操作。这是一个例子。
In [17]: import numpy as np
...: from scipy.stats import entropy
...: from scipy.special import kl_div, rel_entr
p
以和q
为例
。p
具有形状 (3, 5);行是概率分布。q
是一个长度为 5 的一维数组。
In [18]: np.random.seed(8675309)
...: p = np.random.rand(3, 5)
...: p /= p.sum(axis=1, keepdims=True)
...: q = np.random.rand(5)
...: q /= q.sum()
这是您想要的计算,使用 Python 循环和scipy.stats.entropy
. 我将其包含在此处,因此可以将结果与下面的矢量化计算进行比较。
In [19]: [entropy(t, q) for t in p]
Out[19]: [0.32253909299531597, 0.17897138916539493, 0.2627905326857023]
我们构造了p
和,使得每个概率向量之和为 1。在这种情况下,上述结果也可以用或q
进行向量化计算。(我建议. 添加和减去最终会在总和中抵消的附加项,因此它所做的工作比必要的要多。)这些函数仅计算计算的逐点部分;你必须对结果求和才能得到实际的熵或散度。scipy.special.rel_entr
scipy.special.kl_div
rel_entr
kl_div
In [20]: rel_entr(p, q).sum(axis=1)
Out[20]: array([0.32253909, 0.17897139, 0.26279053])
In [21]: kl_div(p, q).sum(axis=1)
Out[21]: array([0.32253909, 0.17897139, 0.26279053])
推荐阅读
- reactjs - 如何修复保护 [api] 的身份验证驱动程序 [jwt] 未定义
- php - Twitter API asatymic/twitter 与 Laravel 8
- discord - 如何使斜线命令机器人不回复消息
- google-cloud-firestore - 计费失败时的 Firestore 触发器行为
- wpf - 当wpf中的datagrid id为空时,如何隐藏菜单上下文?
- openshift - OpenShift:创建构建输入
- c - 如何在 C 编程语言中每次迭代后从 do-while 循环中提取值?
- amazon-web-services - 通过 Terraform 创建的 AWS Glue 中的无效架构错误
- javascript - JavaScript 中的“日期”数据类型是什么?
- r - 检查两个矩阵是否相同