使用numpy计算文本文档之间的Kullback-Leibler(KL)距离

Tig*_*er1 11 numpy distance python-2.7

我的目标是计算以下文本文档之间的KL距离:

1)The boy is having a lad relationship
2)The boy is having a boy relationship
3)It is a lovely day in NY
Run Code Online (Sandbox Code Playgroud)

我首先将文件矢量化,以便轻松应用numpy

1)[1,1,1,1,1,1,1]
2)[1,2,1,1,1,2,1]
3)[1,1,1,1,1,1,1]
Run Code Online (Sandbox Code Playgroud)

然后,我应用以下代码计算文本之间的KL距离:

import numpy as np
import math
from math import log

v=[[1,1,1,1,1,1,1],[1,2,1,1,1,2,1],[1,1,1,1,1,1,1]]
c=v[0]
def kl(p, q):
    p = np.asarray(p, dtype=np.float)
    q = np.asarray(q, dtype=np.float)
    return np.sum(np.where(p != 0,(p-q) * np.log10(p / q), 0))
for x in v:
    KL=kl(x,c)
    print KL
Run Code Online (Sandbox Code Playgroud)

以下是上述代码的结果:[0.0, 0.602059991328, 0.0].文本1和3完全不同,但它们之间的距离为0,而高度相关的文本1和2的距离为0 0.602059991328.这不准确.

有没有人知道我对KL的做法不对?非常感谢你的建议.

dpb*_*dpb 30

虽然我不想添加另一个答案,但这里有两点.首先,正如Jaime在评论中指出的那样,KL分歧(或距离 - 根据以下文档,它们是相同的)旨在衡量概率分布之间的差异.这意味着你传递给函数的基本上应该是两个数组,每个元素的总和为1.

其次,scipy显然确实实现了这一点,其命名方案更多地与信息理论领域相关.功能是"熵":

scipy.stats.entropy(pk, qk=None, base=None)
Run Code Online (Sandbox Code Playgroud)

http://docs.scipy.org/doc/scipy-dev/reference/generated/scipy.stats.entropy.html

来自文档:

如果qk不是None,则计算相对熵(也称为Kullback-Leibler散度或Kullback-Leibler距离)S = sum(pk*log(pk/qk),axis = 0).

这个函数的好处是它会将你传递的向量标准化,如果它们不总和为1(虽然这意味着你必须小心你传递的数组 - 即它们是如何从数据构造的).

希望这会有所帮助,至少有一个库提供它,所以不必编写自己的代码.


J. *_*rde 1

经过一番谷歌搜索以理解 KL 概念后,我认为您的问题是由于向量化造成的:您正在比较不同单词的出现次数。您应该将列索引链接到一个单词,或者使用字典:

#  The boy is having a lad relationship It lovely day in NY
1)[1   1   1  1      1 1   1            0  0      0   0  0]
2)[1   2   1  1      1 0   1            0  0      0   0  0]
3)[0   0   1  0      1 0   0            1  1      1   1  1]
Run Code Online (Sandbox Code Playgroud)

然后你可以使用你的 kl 函数。

要自动矢量化为字典,请参阅如何计算列表中元素的频率?collections.Counter正是您所需要的)。然后你可以循环字典键的并集来计算 KL 距离。