【问题标题】:Efficiently identify duplicates in large list (500,000+)有效识别大型列表中的重复项 (500,000+)
【发布时间】:2017-05-25 23:51:52
【问题描述】:

我有一个大的 DOI 列表,我需要最有效的方法来识别重复的 DOI(即打印出重复值的索引和 DOI。) ​​DOI 的数组可能包含 500,000 + DOI 的。我目前的做法是这样的(inspired by this answer):

from collections import defaultdict
D = defaultdict(list)
for i,item in enumerate(doiList):
    D[item].append(i)
D = {k:v for k,v in D.items() if len(v)>1}
print (D)

有没有更高效的处理方式?

示例 DOI 列表:

doiList = ['10.1016/j.ijnurstu.2017.05.011 [doi]','10.1016/j.ijnurstu.2017.05.011 [doi]' ,'10.1167/iovs.16-20421 [doi]', '10.1093/cid/cix478 [doi]', '10.1038/bjc.2017.133 [doi]', '10.3892/or.2017.5646 [doi]', '10.1177/0961203317711009 [doi]', '10.2217/bmm-2017-0087 [doi]', '10.1007/s12016-017-8611-x [doi]', '10.1007/s10753-017-0594-5 [doi]', '10.1186/s13601-017-0150-2 [doi]', '10.3389/fimmu.2017.00515 [doi]', '10.2147/JAA.S131506 [doi]', '10.2147/JAA.S128431 [doi]', '10.1038/s41598-017-02293-z [doi]', '10.18632/oncotarget.17729 [doi]', '10.1073/pnas.1703683114 [doi]', '10.1096/fj.201600857RRR [doi]', '10.1128/AAC.00020-17 [doi]', '10.1016/j.jpain.2017.04.011 [doi]', '10.1016/j.jaip.2017.04.029 [doi]', '10.1016/j.anai.2017.04.021 [doi]', '10.1016/j.alit.2017.05.001 [doi]']

【问题讨论】:

  • 您期望的重复次数是多少? 10% 是重复的,还是列表的 50% 或 90% 是重复的?
  • @AustinHastings 介于 15-60% 之间
  • 最高效的处理方式还是内存方式?你必须做出权衡......
  • @zwer 处理明智。
  • 也许把它们放到数据库里,让SQL来处理?

标签: python list


【解决方案1】:

尝试将它们存储在 set 中。您可以将重复项附加到单个列表中,这可能会加快速度:

seen = set()
dupes = []

for i, doi in enumerate(doiList):
    if doi not in seen:
        seen.add(doi)
    else:
        dupes.append(i)

此时,seen 包含所有不同的 doi 值,而dupes 包含所有重复值的第 2、3 等索引。您可以在doiList 中查找它们以确定哪个索引对应哪个值。

要从中获得更多性能,您可以缓存方法:

seen = set()
seen_add = seen.add
dupes = []
dupes_append = dupes.append

for i, doi in enumerate(doiList):
    if doi not in seen:
        seen_add(doi)
    else:
        dupes_append(i)

【讨论】:

  • set 是否可以在不使 CPU 过热的情况下处理如此大量的数据?我没有这样的文件来测试您的解决方案。
  • @ChihebNexus 是的,它处理了它,但是速度提升很小。
【解决方案2】:

这是一个完整的解决方案,它返回与您的示例相同的数据集,只是快了两倍多(以一些内存为代价):

def identify_duplicates(data):
    lookup = {}  # store our quick lookup here
    result = {}  # store for our final result
    for i, v in enumerate(data):
        if v in lookup:  # if already in the lookup table it's a duplicate
            if v not in result:  # add it to the result set
                result[v] = lookup[v]
            lookup[v][1] += 1  # increase duplicate count
        else:
            lookup[v] = [i, 0]  # default state for non-duplicates
    return result

print(identify_duplicates(doiList))
# prints: {'10.1016/j.ijnurstu.2017.05.011 [doi]': [0, 1]}

在您的示例中,存储的索引是找到的重复项的第一次出现。如果你想存储所有重复的索引,你可以在lookup[v][1] += 1 行之后添加lookup[v].append(i),但是数据可能看起来很奇怪(结构是[first_index, number_of_occurrences, second_index, third_index...]

而只是翻转lookup[v]修改中存储的参数-lookup[v] = [0, i]而不是lookup[v] = [i, 0]lookup[v][0] += 1而不是lookup[v][1] += 1,然后lookup[v].append(i)会给你一个很好的结果,形式如下: [number_of_occurrences, first_index, second_index, third_index...].

【讨论】:

    猜你喜欢
    • 2011-11-16
    • 2015-01-17
    • 1970-01-01
    • 2011-01-30
    • 2018-11-23
    • 1970-01-01
    • 2017-09-18
    • 1970-01-01
    • 2021-01-03
    相关资源
    最近更新 更多