计算两个列表之间的相似性

时间:2013-02-06 01:54:57

标签: python algorithm set similarity

我想计算两个不同长度的列表之间的相似性。

例如:

listA = ['apple', 'orange', 'apple', 'apple', 'banana', 'orange'] # (length = 6)
listB = ['apple', 'orange', 'grapefruit', 'apple'] # (length = 4)

如您所见,单个项目可以在列表中多次出现,并且长度大小不同。

我已经考虑过比较每个项目的频率,但这并不包含每个列表的大小(一个列表只是另一个列表的两倍应该是相似的,但不完全相似)

EG2:

listA = ['apple', 'apple', 'orange', 'orange']
listB = ['apple', 'orange']
similarity(listA, listB) # should NOT equal 1

所以我基本上想要包含列表的大小以及列表中项目的分布。

有什么想法吗?

3 个答案:

答案 0 :(得分:16)

也许使用collections.Counter();这些是多组或包,用数据类型表示:

from collections import Counter

counterA = Counter(listA)
counterB = Counter(listB)

现在您可以按条目或频率对这些进行比较:

>>> counterA
Counter({'apple': 3, 'orange': 2, 'banana': 1})
>>> counterB
Counter({'apple': 2, 'orange': 1, 'grapefruit': 1})
>>> counterA - counterB
Counter({'orange': 1, 'apple': 1, 'banana': 1})
>>> counterB - counterA
Counter({'grapefruit': 1})

您可以使用以下方法计算余弦相似度:

import math

def counter_cosine_similarity(c1, c2):
    terms = set(c1).union(c2)
    dotprod = sum(c1.get(k, 0) * c2.get(k, 0) for k in terms)
    magA = math.sqrt(sum(c1.get(k, 0)**2 for k in terms))
    magB = math.sqrt(sum(c2.get(k, 0)**2 for k in terms))
    return dotprod / (magA * magB)

给出了:

>>> counter_cosine_similarity(counterA, counterB)
0.8728715609439696

该值越接近1,两个列表越相似。

余弦相似度是您可以计算的一个分数。如果你关心列表的长度,你可以计算另一个;如果你将得分保持在0.0和1.0之间,你可以将这两个值乘以最终得分在-1.0和1.0之间。

例如,要考虑相对长度,您可以使用:

def length_similarity(c1, c2):
    lenc1 = sum(c1.itervalues())
    lenc2 = sum(c2.itervalues())
    return min(lenc1, lenc2) / float(max(lenc1, lenc2))

然后组合成一个以列表作为输入的函数:

def similarity_score(l1, l2):
    c1, c2 = Counter(l1), Counter(l2)
    return length_similarity(c1, c2) * counter_cosine_similarity(c1, c2)  

对于您的两个示例列表,结果为:

>>> similarity_score(['apple', 'orange', 'apple', 'apple', 'banana', 'orange'], ['apple', 'orange', 'grapefruit', 'apple'])
0.5819143739626463
>>> similarity_score(['apple', 'apple', 'orange', 'orange'], ['apple', 'orange'])
0.4999999999999999

您可以根据需要混合其他指标。

答案 1 :(得分:1)

从理论的角度来看:我建议你查看余弦相似度 http://en.wikipedia.org/wiki/Cosine_similarity

您可能需要修改以适合您的方案,但余弦相似性的想法很棒。

答案 2 :(得分:0)

我相信你要找的是计算数组中的反转次数 问题有你的答案:Counting inversions in an array