为定义的对迭代 namedtuple 和 dicts 时速度缓慢

Slowness on iterating over namedtuple and dicts for defined pairs

这段代码 运行 在样本数据上很快,但是当遍历一个大文件时,它似乎 运行 很慢,这可能是因为嵌套的 for 循环。在 defaultdict 中迭代项目很慢还有其他原因吗?

import itertools

sample_genes1={"0002":["GENE1", "GENE2", "GENE3", "GENE4"],
               "0003":["GENE1", "GENE2", "GENE3", "GENE6"],
               "0202":["GENE4", "GENE2", "GENE1", "GENE7"]}

def get_common_gene_pairs(genelist):
    genedict={}
    for k,v in sample_genes1.items():
        listofpairs=[]
        for i in itertools.combinations(v,2):
            listofpairs.append(i)
            genedict[k]=listofpairs
    return genedict

from collections import namedtuple,defaultdict
def get_gene_pair_pids(genelist):
    i=defaultdict(list)
    d=get_common_gene_pairs(sample_genes1)
    Pub_genes=namedtuple("pair", ["gene1", "gene2"])
    for p_id,genepairs in d.iteritems():
        for p in genepairs:
            thispair=Pub_genes(p[0], p[1])
            if thispair in i.keys():
                i[thispair].append(p_id)
            else:
                i[thispair]=[p_id,]
    return i

if __name__=="__main__":
    get_gene_pair_pids(sample_genes1)

一个大问题:这一行:

if thispair in i.keys():

不利用字典搜索,它是线性搜索。放弃 keys() 调用,让字典进行快速查找:

if thispair in i:

但是因为 i 是默认字典,当键不存在时会创建 list,只需替换:

if thispair in i.keys():
    i[thispair].append(p_id)  # i is defaultdict: even if thispair isn't in the dict, it will create a list and append p_id.
else:
    i[thispair]=[p_id,]

通过这个简单的语句:

i[thispair].append(p_id)

(它甚至更快,因为 p_id 只有一个散列)

总结一下:

  • 不要做thispair in i.keys():它很慢,在python 2, or 3, defaultdict or not
  • 您已经定义了一个 defaultdict,但是您的代码只是假定了一个 dict,它可以工作但速度较慢。

注意:如果没有 defaultdict,您可以删除 .keys() 或使用简单的 dict:

i.setdefault(thispair,list)
i[thispair].append(p_id)

(这里默认项取决于key)

旁白:

def get_common_gene_pairs(genelist):
    genedict={}
    for k,v in sample_genes1.items():  # should be genelist, not the global variable, you're not using the genelist parameter at all

而且您根本没有在代码中使用 sample_genes1 的

添加到 ,您的 get_common_gene_pairs 函数可以通过使用 dict comprehension 优化为:

def get_common_gene_pairs(genelist):
    return {k : list(itertools.combinations(v,2)) for k,v in genelist.items()}

list.append()list comprhension 对应部分要耗费更多时间。此外,您不必遍历 itertools.combinations(v,2) 即可将其转换为列表。将其类型转换为 list 即可。

这是我在 list comprehensionlist.append() 之间的比较,以回答 ,如果您有兴趣可以看看。