【问题标题】:Compare multiple Python lists and merge on Levenshtein similarity比较多个 Python 列表并在 Levenshtein 相似性上合并
【发布时间】:2017-07-26 15:42:12
【问题描述】:

我编写了一个 Python 函数,它接受两个列表,使用 Levenshtein 比较它们并将足够相似的单词合并到一个名为“merged”的列表中。

如何为 6 个以上的列表执行此操作?确保将每个列表与其他 5 个列表进行比较等等?

first_list = ["Mouse", "Cat", "Dog", "Gremlinge", "Horse"]
second_list = ["Mouse", "Cat", "Hors", "Dog", "Gremling"]
third_list = ["Mouse", "Cat", "Horrs", "Dog", "Greemling"]
fourth_list = ["Mouse", "Cate", "Dog", "Gremlinge", "Horse"]
fifth_list = ["Mose", "Cat", "Hors", "Dog", "Gremling"]
sixth_list = ["Mouse", "Cat", "Horser", "Doeg", "Gremling"]

def lev_merging(a, b): # function to compare 2 lists
  merged = [] # Empty list to add the matching words
  for first in a:
    for second in b:
      if levenshtein(first, second) < 2:
        merged.append(set([first,second]))
  return merged

print (lev_merging(first_list,second_list))

Working www.repl.it fiddle of code.

【问题讨论】:

  • 所以你想比较first_list中的每个单词和second_list中的每个单词?
  • 感谢您的评论。不,这就是我的功能目前所做的。我已经更新了帖子以显示其他 4 个列表,我希望我的函数也可以通过并合并相似性。
  • 您能否提供您正在寻找的示例输出?您是否正在寻找单个列表的结果,其中列表中的每个元素都是所有列表中所有“关闭”单词的集合。所以[{"Mouse","Mose"}, {"Cat", "Cate"}, ...]
  • 是的,谢谢,这正是我要找的。最好我也想只将“关闭”词合并到他们自己的列表中,如果它们来自 3 个或更多列表,我想这需要某种计数器?

标签: python list function compare levenshtein-distance


【解决方案1】:

我们会有一个字符串列表

list_of_lists = [["Mouse", "Cat", "Dog", "Gremlinge", "Horse"],
                  ["Mouse", "Cat", "Hors", "Dog", "Gremling"],
                  ["Mouse", "Cat", "Horrs", "Dog", "Greemling"],
                  ["Mouse", "Cate", "Dog", "Gremlinge", "Horse"],
                  ["Mose", "Cat", "Hors", "Dog", "Gremling"],
                  ["Mouse", "Cat", "Horser", "Doeg", "Gremling"]]

然后我们将遍历这个列表,跟踪我们“所在”的列表的索引,并将这个列表与它之后的所有列表进行比较。

def merging(list_of_lists):
    merged = []
    for i, a in enumerate(list_of_lists):
        for b in list_of_lists[i+1:]:
            for first in a:
                for second in b:
                    if lev(first, second) < 2:
                        merged.append((first, second))
    return merged

编辑:下面的代码将成对的列表传递给一个函数,并将它们分成组。然后我们会将这些组中的每一个处理成集合,以删除重复项。

target_num_words = 6
target_num_words

def merging(list_of_lists):
    groups = []
    for i, a in enumerate(list_of_lists):
        for b in list_of_lists[i+1:]:
            if number_of_matches(a, b) >= target_num_words:
                for g in groups:
                    if a in g or b in g:
                        g.append(a if b in g else b)
                        break
                else:
                    groups.append([a, b])
    merged = []
    for g in groups:
        if len(g) >= target_num_lists:
            merged.append({x for l in g for x in l})
    return merged

number_of_matches 基本上是您的 Levenshtein 代码,除了它只返回两个列表之间的匹配单词数。即使这不是您想要的,这也应该让您了解如何到达那里。

【讨论】:

  • 这真是太棒了,正是我想要的!但是,是否有可能以某种方式将相似的单词分组并排除/删除重复项?如果合并了 >3 个列表,是否可以仅返回合并?
  • 你会如何对它们进行分组?如果AB 足够相似且BC 足够相似,即使AC 不相似,A BC 也在同一组中?
  • 非常好的问题。我实际上正在寻找一种解决方案,该解决方案将根据匹配或“关闭”单词的数量以及这些单词来自的列表数量将列表合并到单独的列表中。所以想象有 3 个列表,其中有 6 个匹配的动物词:List AList BList C,我希望这些在 List 1 中合并在一起,没有重复。但是 List DList E 有 6 个关于其他内容的匹配词,不会匹配,仅来自 2 个列表。如果List AList BList C的匹配词少于6个,它们也不会被合并。
  • 您的编辑看起来很棒,看起来就像我要找的一样。虽然恐怕我不明白 if number_of_matches(a, b) &gt;= target_num_words: 行?我怎样才能调用这样的变量?还是我完全误解了什么?这是您建议我添加和重写 Levenshtein 脚本的地方吗?
  • number_of_matches 将是一个函数(我没有写,因为它并不真正相关),它接受两个列表并返回这两个列表之间的匹配数
【解决方案2】:

这个答案有两个解决方案。对于这两者,您需要创建一个列表,其中包含您要比较的所有列表。

例如,使用上述案例,您将执行以下操作:

lists = [first_list, second_list]

ITERTOOLS 解决方案

在此解决方案中,您使用itertools.combinations 方法,该方法遍历所有可能的组合,这意味着它将每个列表与每个其他列表进行比较。你可以这样实现它:

import itertools
for a, b in itertools.combinations(lists, 2):
    for first in a:
        for second in b:
            if levenshtein(first, second) < 2:
                merged.append(first)

itertools.combinations 方法有两个参数,第一个是可迭代的,第二个是每个组合中元素的数量。在这种情况下 2. 例如:

itertools.combinations('ABCD', 2)

返回:

('A', 'B')
('A', 'C')
('A', 'D')
('B', 'C')
('B', 'D')
('C', 'D')

和:

itertools.combinations('ABCD', 3)

返回:

('A', 'B', 'C')
('A', 'B', 'D')
('A', 'C', 'D')
('B', 'C', 'D')

FOR LOOP 解决方案

如果您不想导入一些奇怪的模块,请不要担心。您始终可以使用这个解决方案,它只需要 2 个 for 循环。

for i in range(len(lists)):
    for j in range(i + 1, len(lists)):
        for first in lists[i]:
            for second in lists[j]:
                if levenshtein(first, second) < 2:
                    merged.append(set([first,second]))

通过这样做,您可以成功地将每个列表中的每个项目与其他列表中的每个项目进行比较,而无需将两个列表进行两次比较。

【讨论】:

  • 这也正是我要找的,谢谢。使用 itertools 在速度方面有什么优势吗?另外,是否可以根据单词组对结果列表进行分组并消除重复项?那么,Horse、Horser 和 Hors 将分组并只出现一次?
  • Itertools 是用 C 编写的,所以我相信由于 C 比 Python 快 400 倍,因此该模块应该快得多。但是,我并不完全确定。
猜你喜欢
  • 2011-06-12
  • 2023-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多