Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/335.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
Python 计算两个列表之间的相似性_Python_Algorithm_Set_Similarity - Fatal编程技术网

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

Python 计算两个列表之间的相似性,python,algorithm,set,similarity,Python,Algorithm,Set,Similarity,我想计算两个不同长度的列表之间的相似性 例如: 如您所见,单个项目可以在列表中多次出现,并且长度大小不同 我已经考虑过比较每个项目的频率,但这并不包括每个列表的大小(一个列表是另一个列表的两倍,应该是相似的,但不是完全相似的) eg2: 所以我基本上想包括列表的大小,以及列表中项目的分布 有什么想法吗?也许用吧;用数据类型的说法,这些是多集或包: from collections import Counter counterA = Counter(listA) counterB = Count

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

例如:

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

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

eg2:

所以我基本上想包括列表的大小,以及列表中项目的分布

有什么想法吗?

也许用吧;用数据类型的说法,这些是多集或包:

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

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

从理论角度来看:我建议您查找余弦相似性


您可能需要修改以适应您的方案,但余弦相似性的想法非常好。

我相信您要寻找的是计算数组中的反转数
问题的答案是:

这些是列表,而不是集合。通过
相似性
,您的意思是创建第三个列表,其中包含同时出现在listA和listB中的元素吗?因此,在你的例子中,结果将是
['apple','orange']
?我所说的相似性是指它们之间的相似程度。因此,比较两个相同的集合(或列表)会得到1分,而两个完全不同的集合会得到零分。然而,这些集合的大小不同,可能包含重复的元素这类作品,但是如果我们看一个例子,列表c1只是c2的两倍,那么相似性仍然是1。所以这不是我想要的。谢谢你的代码。@kamula:这是一个起点;如果cos相似度为1,请查看其中一个列表的顶部计数是否比另一个列表的顶部计数要大(
.most_common(1)
),以进行调整,等等。如果您不希望得到余弦距离提供的长度标准化分数,您可以计算两个列表之间的欧几里德距离。很抱歉,但我不确定是否明白您的意思。在合并排序的实现中,如何将比较两个集合转换为计算反转数?
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