我有两个清单:
例如。 a = [1,8,3,9,4,9,3,8,1,2,3] 和 b = [1,8,1,3,9,4,9,3,8,1,2,3]
两者都包含整数。整体背后没有任何意义(例如,1不是'更接近'3而不是8')。
我正在尝试设计一种算法来计算两个ORDERED列表之间的相似性。 Ordered是关键字就在这里(所以我不能只取两个列表的集合并计算它们的set_difference百分比)。有时数字会重复(例如上面的3,8和9,我不能忽略重复)。
在上面的例子中,我打电话的函数会告诉我a和b的相似度约为90%。我怎样才能做到这一点?编辑距离是我想到的。我知道如何使用字符串,但我不知道如何使用它与一个整数列表。谢谢!
答案 0 :(得分:22)
您可以使用difflib模块
比率()
将序列相似性的度量返回为[0,1]范围内的浮点数。
给出了:
>>> s1=[1,8,3,9,4,9,3,8,1,2,3]
>>> s2=[1,8,1,3,9,4,9,3,8,1,2,3]
>>> sm=difflib.SequenceMatcher(None,s1,s2)
>>> sm.ratio()
0.9565217391304348
答案 1 :(得分:12)
听起来,编辑(或Levenshtein)距离恰好是工作的正确工具。
这是一个可以在整数列表上使用的Python实现:http://hetland.org/coding/python/levenshtein.py
使用该代码,levenshtein([1,8,3,9,4,9,3,8,1,2,3], [1,8,1,3,9,4,9,3,8,1,2,3])
会返回1
,这是编辑距离。
考虑到编辑距离和两个数组的长度,计算“百分比相似度”指标应该是非常简单的。
答案 2 :(得分:3)
如果值没有任何特殊含义,只需使用相同的算法计算字符串上的编辑距离。
答案 3 :(得分:3)
解决此问题的一种方法是使用histogram。作为示例(使用numpy进行演示):
In []: a= array([1,8,3,9,4,9,3,8,1,2,3])
In []: b= array([1,8,1,3,9,4,9,3,8,1,2,3])
In []: a_c, _= histogram(a, arange(9)+ 1)
In []: a_c
Out[]: array([2, 1, 3, 1, 0, 0, 0, 4])
In []: b_c, _= histogram(b, arange(9)+ 1)
In []: b_c
Out[]: array([3, 1, 3, 1, 0, 0, 0, 4])
In []: (a_c- b_c).sum()
Out[]: -1
现在有很多方法可以利用a_c
和b_c
。
(看似)最简单的相似性度量是:
In []: 1- abs(-1/ 9.)
Out[]: 0.8888888888888888
其次是:
In []: norm(a_c)/ norm(b_c)
Out[]: 0.92796072713833688
和
In []: a_n= (a_c/ norm(a_c))[:, None]
In []: 1- norm(b_c- dot(dot(a_n, a_n.T), b_c))/ norm(b_c)
Out[]: 0.84445724579043624
因此,您需要更具体地找出适合您目的的最合适的相似性度量。
答案 4 :(得分:0)
除非我忽略了这一点。
from __future__ import division
def similar(x,y):
si = 0
for a,b in zip(x, y):
if a == b:
si += 1
return (si/len(x)) * 100
if __name__ in '__main__':
a = [1,8,3,9,4,9,3,8,1,2,3]
b = [1,8,1,3,9,4,9,3,8,1,2,3]
result = similar(a,b)
if result is not None:
print "%s%s Similar!" % (result,'%')
答案 5 :(得分:0)
很久以前,我已经为类似的任务实施了一些东西。现在,我只有a blog entry for that。这很简单:你必须计算两个序列的pdf,然后它会找到pdf的图形表示覆盖的公共区域。
很抱歉链接上的图像损坏,我当时使用的外部服务器已经死了。
目前,针对您的问题,代码转换为
def overlap(pdf1, pdf2):
s = 0
for k in pdf1:
if pdf2.has_key(k):
s += min(pdf1[k], pdf2[k])
return s
def pdf(l):
d = {}
s = 0.0
for i in l:
s += i
if d.has_key(i):
d[i] += 1
else:
d[i] = 1
for k in d:
d[k] /= s
return d
def solve():
a = [1, 8, 3, 9, 4, 9, 3, 8, 1, 2, 3]
b = [1, 8, 1, 3, 9, 4, 9, 3, 8, 1, 2, 3]
pdf_a = pdf(a)
pdf_b = pdf(b)
print pdf_a
print pdf_b
print overlap(pdf_a, pdf_b)
print overlap(pdf_b, pdf_a)
if __name__ == '__main__':
solve()
不幸的是,它给出了一个意想不到的答案,只有0.212292609351
答案 6 :(得分:0)
@kraymer 提出的解决方案不适用于
s1=[1,2,3,4,5,6,7,8,9,10]
s2=[2,1,3,4,5,6,7,8,9,9]
因为它返回 0.8,即使有 3 个不同的元素而不是 2 个。
解决方法可能是:
def find_percentage_agreement(s1, s2):
assert len(s1)==len(s2), "Lists must have the same shape"
nb_agreements = 0 # initialize counter to 0
for idx, value in enumerate(s1):
if s2[idx] == value:
nb_agreements += 1
percentage_agreement = nb_agreements/len(s1)
return percentage_agreement
返回预期结果:
>>> s1=[1,2,3,4,5,6,7,8,9,10]
>>> s2=[2,1,3,4,5,6,7,8,9,9]
>>> find_percentage_agreement(s1, s2)
0.7