11

我的目标是计算以下文本文档之间的 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

我首先对文档进行了矢量化,以便轻松应用 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]

然后我应用以下代码来计算文本之间的 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

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

有人知道我在 KL 方面做得不对吗?非常感谢您的建议。

4

3 回答 3

30

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

其次,scipy 显然确实实现了这一点,其命名方案与信息论领域更相关。函数是“熵”:

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

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,它将对传递它的向量进行归一化(尽管这意味着你必须小心传递的数组 - 即它们是如何从数据构造的)。

希望这会有所帮助,并且至少有一个库提供了它,因此不必编写自己的代码。

于 2014-07-08T19:17:16.407 回答
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]

然后你可以使用你的 kl 功能。

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

于 2013-08-22T14:19:29.083 回答
0

一个潜在的问题可能出现在您对 KL 的 NP 定义中。阅读公式的维基百科页面:http ://en.wikipedia.org/wiki/Kullback%E2%80%93Leibler_divergence

请注意,您将 (pq) 乘以日志结果。根据 KL 公式,这应该只是 p:

 return np.sum(np.where(p != 0,(p) * np.log10(p / q), 0))

这可能会有所帮助...

于 2014-04-03T20:56:32.147 回答