不同长度向量的余弦相似度?

15

我正在尝试使用TF-IDF将文档分类。我已经计算了一些文档的tf_idf,但是当我尝试计算两个这些文档之间的余弦相似度时,出现了一个回溯错误:

#len(u)==201, len(v)==246

cosine_distance(u, v)
ValueError: objects are not aligned

#this works though:
cosine_distance(u[:200], v[:200])
>> 0.52230249969265641

将向量切片以使len(u)==len(v)是正确的方法吗?我认为余弦相似度可以处理长度不同的向量。

我正在使用这个函数

def cosine_distance(u, v):
    """
    Returns the cosine of the angle between vectors v and u. This is equal to
    u.v / |u||v|.
    """
    return numpy.dot(u, v) / (math.sqrt(numpy.dot(u, u)) * math.sqrt(numpy.dot(v, v))) 

另外,tf_idf向量中的值的顺序是否重要?它们应该被排序吗,还是对于此计算来说无关紧要?

3个回答

11
你需要对应单词在向量中进行乘法运算,因此单词应该有一个全局的顺序。理论上,你的向量应该具有相同的长度。
实际上,如果先看到一个文档,那么第二个文档中的单词可能会被添加到全局顺序中,因此即使这些向量有相同的顺序,第一个文档可能会更短,因为它没有那些未包含在该向量中的单词的条目。
文档1:The quick brown fox jumped over the lazy dog.
Global order:     The quick brown fox jumped over the lazy dog
Vector for Doc 1:  1    1     1    1     1     1    1   1   1

第二个文档: 跑步者很快。

Global order:     The quick brown fox jumped over the lazy dog runner was
Vector for Doc 1:  1    1     1    1     1     1    1   1   1
Vector for Doc 2:  1    1     0    0     0     0    0   0   0    1     1
在这种情况下,理论上您需要在文档1向量末尾填充零。实际上,在计算点积时,您只需要将元素乘到向量1的末尾(因为省略向量2的额外元素并将它们乘以零与访问额外元素相同,但访问额外元素会更慢)。
然后,您可以分别计算每个向量的大小,对于这一步来说,向量不需要具有相同的长度。

在计算余弦相似度时,填充的零确实会产生影响。我使用的余弦相似度函数是: 余弦相似度 = 点积(u, v) / sqrt(点积(u, u)) * sqrt(点积(v, v))余弦相似度([1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1]) == 0.3333333333333333余弦相似度([1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 0, 0, 0, 0, 0]) == 0.4714045207910316看起来问题在于余弦相似度的除数执行了自身的点积。因此,填充确实会产生影响。你知道有什么解决办法吗? - erikcw
@erikcw:当计算Doc1*Doc1的点积时,您需要到达Doc1的完整长度,但不需要超过。对于Doc2*Doc2,则需要到达Doc2的完整长度,但不需要超过。在点积的这一部分中,不要截断较长的向量,但无需填充较短的向量。但是,在计算Doc1*Doc2时,您可以安全地截断较长的向量。因此,您的代码应该设计为让“点积”函数做出关于填充/截断的决策,而不是让“余弦相似性”函数做出这些决策。 - Ken Bloom
@larsmans:第二张图中向量长度不匹配是有意为之的。 - Ken Bloom
@KenBloom:好的,抱歉! - Fred Foo

6

你是否在计算词向量的余弦相似度?词向量应该具有相同的长度。如果文档中没有出现某些单词,则该单词的值应为0。

我不确定你正在应用余弦相似度的向量是什么,但当使用余弦相似度时,向量应始终具有相同的长度,顺序非常重要。

例如:

Term | Doc1 | Doc2
Foo     .3     .7
Bar  |  0   |  8
Baz  |  1   |  1

这里有两个向量(.3,0,1)和(.7,8,1),可以计算它们之间的余弦相似度。如果你比较(.3,1)和(.7,8),你将会比较Baz文档中的Doc1得分与Bar文档中的Doc2得分,这样是没有意义的。


我传递给cosine_distance函数的向量是Python列出的tf-idf值列表。v[:5] == [0.0060830126968545294,0.00048241996565891193,0.0020712248617478965,0.0110036199241575,0.0110036199241575]你说顺序很重要——按照什么方式对向量内容进行排序才是正确的(从小到大、文档中单词的顺序等)? - erikcw
你需要为单词分配一些全局顺序。如果在doc2中bar出现在foo之前,则bar的tf_idf值仍应该是第一项。 - Pace

5

在将向量输入cosine_distance函数之前,尝试先构建它们:

import math
from collections import Counter
from nltk import cluster

def buildVector(iterable1, iterable2):
    counter1 = Counter(iterable1)
    counter2= Counter(iterable2)
    all_items = set(counter1.keys()).union( set(counter2.keys()) )
    vector1 = [counter1[k] for k in all_items]
    vector2 = [counter2[k] for k in all_items]
    return vector1, vector2


l1 = "Julie loves me more than Linda loves me".split()
l2 = "Jane likes me more than Julie loves me or".split()


v1,v2= buildVector(l1, l2)
print(cluster.util.cosine_distance(v1,v2))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接