筛选列表以删除类似但不相同的条目

时间:2013-05-20 10:27:34

标签: python python-3.x

我有一个包含数千个名称的长列表,这些名称都是唯一的字符串,但我想过滤它们以生成一个较短的列表,这样如果有相似的名称,则只保留一个。例如,原始列表可以包含:

米老鼠

Mickey M Mouse

Mickey M. Mouse

新列表只包含其中一个 - 此时此刻并不重要。可以使用下面的代码获得相似性分数(其中 a b 是要比较的文本),所以如果我选择一个合适的比例,我有办法做出包含/排除决定。

difflib.SequenceMatcher(None, a, b).ratio()

我正在努力解决的问题是如何填充第一个列表中的第二个列表。我确定这是一个微不足道的事情,但它让我的新手脑子感到困惑。

我已经想到了一些可行的方法,但最终没有任何内容填充在第二个列表中。

for p in ppl1:
    for pp in ppl2:
       if difflib.SequenceMater(None, p, pp).ratio() <=0.9:
           ppl2.append(p)

事实上,即使确实填写了这个列表,它仍然是错误的。我想它需要将第一个列表中的名称与第二个列表中的所有名称进行比较,跟踪得分最高的比率,然后仅在最高比率低于截止标准时才添加它。

感激地收到任何指导!

2 个答案:

答案 0 :(得分:1)

我将冒险永远不会接受,因为这可能对您来说太高级了,但这是最佳解决方案。

您要做的是agglomerative clustering的变体。可以使用union-find algorithm来有效地解决这个问题。从所有不同的字符串ab对,可以使用

生成
def pairs(l):
    for i, a in enumerate(l):
        for j in range(i + 1, len(l)):
            yield (a, l[j])

您过滤具有相似比率<= .9的对:

similar = ((a, b) for a, b in pairs
                  if difflib.SequenceMatcher(None, p, pp).ratio() <= .9)

然后将disjoint-set forest中的人联合起来。在那之后,你循环遍历集合以获得他们的代表。

答案 1 :(得分:0)

首先,在您对列表进行迭代时,不应该修改列表。

一种策略是遍历所有名称对,如果某个对彼此太相似,只保留一个,然后迭代这个,直到没有两个对太相似。当然,结果现在取决于列表的初始顺序,但是如果您的数据充分聚集并且您的相似性得分指标足够好,那么它应该产生您正在寻找的内容。