Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
计算Kullback的有效方法–;Python中的Leibler分歧_Python_Performance_Numpy_Scipy_Statistics - Fatal编程技术网

计算Kullback的有效方法–;Python中的Leibler分歧

计算Kullback的有效方法–;Python中的Leibler分歧,python,performance,numpy,scipy,statistics,Python,Performance,Numpy,Scipy,Statistics,我必须计算数千个离散概率向量之间的(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):

我必须计算数千个离散概率向量之间的(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, :])
默认情况下,Scipy以1D数组的形式邀请输入,给我们一个标量,这在列出的问题中完成。在内部,这个函数也允许,我们可以在这里滥用它来获得矢量化的解决方案

从-

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

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

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

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

现在,这里的问题是,
stats.entropy()
将沿着
轴=0
求和,因此我们将向它提供两个版本的
分布
,这两个版本的分布都将把生长维度带到
轴=0
,以便沿着它进行缩减,另外两个轴交错-
(M,1)
&
(1,M)
给我们一个
(M,M)
形状的输出阵列,使用
广播

因此,解决我们的问题的矢量化且更有效的方法是-

from scipy import stats
kld = stats.entropy(distributions.T[:,:,None], distributions.T[:,None,:])
运行时测试和验证-

In [15]: def entropy_loopy(distrib):
    ...:     n = distrib.shape[0] #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] = stats.entropy(distrib[i, :], distrib[j, :])
    ...:     return kld
    ...: 

In [16]: distrib = np.random.randint(0,9,(100,100)) # Setup input

In [17]: out = stats.entropy(distrib.T[:,:,None], distrib.T[:,None,:])

In [18]: np.allclose(entropy_loopy(distrib),out) # Verify
Out[18]: True

In [19]: %timeit entropy_loopy(distrib)
1 loops, best of 3: 800 ms per loop

In [20]: %timeit stats.entropy(distrib.T[:,:,None], distrib.T[:,None,:])
10 loops, best of 3: 104 ms per loop

美丽的。谢谢你。@Amir很乐意帮忙。甚至我都不知道scipy的熵会支持广播,它确实支持,这是NumPy最好的东西!这正是我的想法,这让我甚至不去尝试它!你能给我一个关于你为什么写这样的矩阵变量“distrib.T[:,:,None]”和“distrib.T[:,None,:]”的参考吗?“无”的作用是什么?为什么要转置这两个矩阵?@Amir表示“无”或将引入单体维度,或是将维度从现有二维数组形状扩展到三维数组的方法。这种转置是必要的,因为在内部,函数求和横轴=0,这是为了复制所有元素相乘元素的和,我们将在每次迭代的问题循环代码中得到这些元素。希望这是有意义的@KillianTattan我猜
stats.entropy(分布[0,无].T,分布[1:].T)
。如何使用scipy获得python中具有最小KL散度的概率分布生成器?