解读scipy.stats.entropy值
我正在尝试使用 scipy.stats.entropy 来估算两个分布之间的 Kullback–Leibler (KL) 散度。更具体地说,我想用 KL 散度作为一个指标,来判断这两个分布的一致性。
但是,我对 KL 值的理解有些困惑。例如:
t1=numpy.random.normal(-2.5,0.1,1000)
t2=numpy.random.normal(-2.5,0.1,1000)
scipy.stats.entropy(t1,t2)
结果是 0.0015539217193737955
接着,
t1=numpy.random.normal(-2.5,0.1,1000)
t2=numpy.random.normal(2.5,0.1,1000)
scipy.stats.entropy(t1,t2)
结果是 0.0015908295787942181
为什么两个完全不同的分布,几乎没有重叠,却有相同的 KL 值呢?
t1=numpy.random.normal(-2.5,0.1,1000)
t2=numpy.random.normal(25.,0.1,1000)
scipy.stats.entropy(t1,t2)
结果是 0.00081111364805590595
这个结果的 KL 值甚至更小(也就是说,距离更近),我本能地会认为这表示“更一致”。
在这种情况下,如何理解 scipy.stats.entropy(即 KL 散度距离)呢?
1 个回答
numpy.random.normal(-2.5,0.1,1000)
是从一个正态分布中抽取的样本。简单来说,就是生成了1000个随机数字,顺序是乱的。关于 entropy
的文档里提到:
pk[i]
是事件i
的(可能是未归一化的)概率。
所以,要想得到有意义的结果,你需要让这些数字“对齐”,也就是说,相同的索引要对应到分布中的相同位置。在你的例子中,t1[0]
和 t2[0]
之间没有任何关系。你的样本并没有直接告诉你每个值的“可能性”,而这是计算KL散度所需要的;它只是给你提供了一些从分布中抽取的实际值。
获取对齐值的最简单方法是,在一些固定的值上评估分布的概率密度函数。为此,你需要使用 scipy.stats.norm
(这会生成一个可以以各种方式操作的分布对象),而不是 np.random.normal
(它只返回抽样值)。下面是一个例子:
t1 = stats.norm(-2.5, 0.1)
t2 = stats.norm(-2.5, 0.1)
t3 = stats.norm(-2.4, 0.1)
t4 = stats.norm(-2.3, 0.1)
# domain to evaluate PDF on
x = np.linspace(-5, 5, 100)
然后:
>>> stats.entropy(t1.pdf(x), t2.pdf(x))
-0.0
>>> stats.entropy(t1.pdf(x), t3.pdf(x))
0.49999995020647586
>>> stats.entropy(t1.pdf(x), t4.pdf(x))
1.999999900414918
你会看到,当分布之间的距离越来越远时,它们的KL散度也会增加。(实际上,使用你的第二个例子会得到一个KL散度为 inf
,因为它们几乎没有重叠。)