在Python中计算Kullback-Leibler分歧的有效方法

时间:2015-11-30 20:06:44

标签: python performance numpy scipy statistics

我必须计算数千个离散概率向量之间的Kullback-Leibler Divergence(KLD)。目前我使用的是以下代码,但对于我的目的而言,它太慢了。我想知道是否有更快的方法来计算KL发散?

import numpy as np
import scipy.stats as sc

    #n is the number of data points
    kld = np.zeros(n, n)
        for i in range(0, n):
            for j in range(0, n):
                if(i != j):
                    kld[i, j] = sc.entropy(distributions[i, :], distributions[j, :])

1 个答案:

答案 0 :(得分:11)

Scipy的stats.entropy在其默认意义上邀请输入作为一维数组给我们一个标量,这是在列出的问题中完成的。在内部,此功能还允许broadcasting,我们可以滥用在这里为矢量化解决方案。

来自docs -

  

scipy.stats.entropy(pk,qk = None,base = None)

     

如果只有概率pk   给出,熵计算为S = -sum(pk * log(pk),   轴= 0)。

     

如果qk不是None,则计算Kullback-Leibler散度S =   sum(pk * log(pk / qk),axis = 0)。

在我们的例子中,我们针对所有行对每一行进行这些熵计算,执行求和减少以在每次迭代时使用这两个嵌套循环具有标量。因此,输出数组的形状为(M,M),其中M是输入数组中的行数。

现在,这里的问题是stats.entropy()将与axis=0相加,因此我们将为其提供两个版本的distributions,这两个版本都会将行标题带到{沿着它减少{1}}和其他两个交错的轴 - axis=0& (M,1)使用(1,M)为我们提供(M,M)形状的输出数组。

因此,解决我们案例的矢量化和更有效的方法是 -

broadcasting

运行时测试和验证 -

from scipy import stats
kld = stats.entropy(distributions.T[:,:,None], distributions.T[:,None,:])