计算嵌套列表长度不等的多个元素的相似度

时间:2016-03-27 03:05:18

标签: python list similarity

我有一个嵌套列表,每个第二个元素都有不同的长度:

lst = [[a,bcbcbcbcbc],[e,bbccbbccb],[i,ccbbccbb],[o,cbbccbb]]

我的输出是具有这种外观的数据帧的csv:

comparison     similarity_score
   a:e          *some score      
   a:i          *some score
   a:o          *some score
   e:i          *some score
   e:o          *some score
   i:o          *some score

我的代码:

similarity = []
for i in lst:
    name = i[0]
    string = i[1]
    score = 0.0
    length =(len(string))
    for i in range(length):
        if string[i]==string[i+1]:
            score += 1.0
    new_score = (100.0*score)/length
    name_seq = name[i] + ':' + name[i+1]
    similarity.append(name_seq,new_score)

similarity.pdDataFrame(similarity, columns = ['comparison' , 'similarity_score'])
similarity.to_csv('similarity_score.csv')

但是我收到了一个错误:

    if codes[i]==codes[i+1]:
          IndexError: string index out of range

任何建议?谢谢!

2 个答案:

答案 0 :(得分:1)

根据Python的文档range通过示例执行以下操作:

  

>>>范围(10)
  [0,1,2,3,4,5,6,7,8,9]

在您的代码中(假设变量名称未更改):

...
length =(len(string))            # For an input of 'bcb' length will be 3
for i in range(length):          # For an input of 'bcb' range will be [0, 1, 2]
    if string[i]==string[i+1]:   # When i == 2 i + 1 == 3 which gives you the
                                 # IndexError: string index out of range
...

换句话说,给定输入bcb,if语句将查看以下索引:

(0,1)
(1,2)
(2,3)<--在这种情况下,3是你的问题。

要解决您的问题,请从[0, len(string) - 1]

进行迭代

答案 1 :(得分:1)

我认为你最大的问题是,在顶层你只是一次迭代一对name,string对,而不是像你想要在你的身上看到的一对name,string对输出(如配对名称a:e所示)。

您之后尝试将namestring值编入索引,但这样做并不能达到您想要的效果(将两个字符串相互比较以计算得分),因为您只能访问同一字符串中的相邻字符。您获得的例外情况是因为i+1可能会脱离字符串的末尾。由于您对内循环中的索引使用i以及从外循环(name, string对)中获取的项目,因此存在进一步的混淆。

要获得成对配对,我建议使用itertools.combinations

import itertools

for [name1, string1], [name2, string2] in itertools.combinations(lst, 2):

现在你可以在循环的其余部分使用两个名字和两个字符串变量。

我不完全确定我理解你想要比较字符串以获得你的分数,因为它们的长度不一样。如果只想比较字符串的初始部分(并忽略较长部分的尾部位),可以使用zip在两个字符串之间获取相应字符对。然后,您可以在生成器表达式中对它们进行比较,并将bool结果相加(True是整数1的特殊版本,False是{{1}的版本}})。然后你可以除以字符串长度中较小的一个(如果你想惩罚长度差异,可以更大):

0

还有一个更明显的问题,即你用两个参数调用common_letters = sum(c1 == c2 for c1, c2 in zip(string1, string2)) new_score = common_letters * 100 / min(len(string1), len(string2)) 。如果你真的想要附加一个2元组,你需要一组额外的括号:

append