2016-03-27 46 views
0

我有一个嵌套列表的多个元素的相似性,与每一个第二元件,其具有变化的长度:计算具有不相等长度的嵌套列表

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') 

但我recieving一个错误:

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

有什么建议吗?谢谢!

+0

numPlaces在哪里初始化?代码[i] ==代码[i + 1]不会出现在您的代码片段中,除非您的意思是string [i] == string [i + 1] – elhefe

+0

什么是'numPlaces'(也许它应该是'length ')?为什么你的例外中的行不符合你所显示代码中的任何一行?无论如何,我认为你对'i'感到困惑,因为你在不同的时间使用同一个变量名称来处理两个不同的事情。如果'name'在你的列表中是'a',那么你做'name [i + 1]'的地方根本没有任何意义。 – Blckknght

+0

@Blckknght感谢您的更正。我不得不承认我很困惑于我在for循环中。 –

回答

1

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

>>>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

解决您的问题迭代我觉得你最大的问题是,在顶层你只是迭代上一个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的特殊版本,而False0的版本)。然后,您可以通过字符串的长度的小分(或者较大的,如果你想惩罚长度差异):

common_letters = sum(c1 == c2 for c1, c2 in zip(string1, string2)) 
new_score = common_letters * 100/min(len(string1), len(string2)) 

还有一个比较明显的问题,在您使用两个参数调用append。如果你真的想要追加一个2元组,你需要一组额外的圆括号:

similarity.append((name_seq, new_score))