python – 如何加速400万集交叉点?

我是一名缺乏经验的程序员,正在通过
Python进行大量的生物信息学练习.

一个问题区域计算名称组之间的集合交集中的元素,以及计算在字典中的存储.每个列表有两个2000个名称组;名称组中的名称是物种的拉丁名称.例如:

list__of_name_groups_1 = [
    ['Canis Lupus', 'Canis Latrans'],
    ['Euarctos Americanus', 'Lynx Rufus'],
    ...
]
list__of_name_groups_2 = [
    ['Nasua Narica', 'Odocoileus Hemionus'],
    ['Felis Concolor', 'Peromyscus Eremicus'],
    ['Canis Latrans', 'Cervus Canadensis']
    ...
]

我需要一个字典,其中包含名称组之间的所有交叉点大小,例如

>>> intersections
{ (0, 0): 0, (0, 1): 0, (0, 2): 1, (1, 0): 0, (1, 1): 0, (2, 1): 0,
  (2, 0): 1, (2, 1): 0, (2, 2): 0 }

(‘Canis Latrans’出现在第一个列表的元素0中,第二个列表中的元素2出现.)

我有一个有效的算法实现,但运行速度太慢.

overlap = {}
    for i in list_of_lists_of_names_1:            
        for j in list_of_lists_of_names_2:
            overlap[(i,j)] = len(set(i) & set(j))

有没有更快的方法来计算集合交叉点中的元素数量?

(你好主持人……尼克,这个修改过的帖子实际上问的问题与我正在处理的问题略有不同.虽然你的答案对于解决这个问题非常好,但我担心你建议的方法是实际上对我正在尝试做的事情没有用.我非常感谢你在答案中付出的时间和精力,以及编辑这篇文章,但我会要求将这篇文章还原为原文.)

最佳答案 首先,Python集很擅长查找交集(它们使用散列),但是您的代码反复构造相同的集合.例如.如果这两个列表各包含2000个元素[你的意思是外部或内部列表那么长吗?],只有4000个不同的集合要计算,但你的代码计算2000 x 2000 x 2 = 800万集.

所以计算一次4000套:

list_of_name_tuples_1 = [("a", "aa"), ("b", "bbb"), ("c", "cc", "ccc")]
list_of_name_tuples_2 = [("a", "AA"), ("b", "BBB"), ("c", "cc", "CCC")]
name_sets_1 = [set(i) for i in list_of_name_tuples_1]
name_sets_2 = [set(i) for i in list_of_name_tuples_2]

overlap = {}
for l1, s1 in zip(list_of_name_tuples_1, name_sets_1):
    for l2, s2 in zip(list_of_name_tuples_2, name_sets_2):
        overlap[(l1, l2)] = len(s1 & s2)

Python列表是不可删除的,因此它们不能用于dict键,因此我将名单列表更改为名称列表.

(此代码假设您正在使用Python 3,其中zip()返回迭代器.如果您使用的是Python 2,则调用itertools.izip()以获取配对元素上的迭代器.)

其次,考虑将重组重叠视为一个词典,而不是一个由元组索引的词典.

list_of_name_tuples_1 = [("a", "aa"), ("b", "bbb"), ("c", "cc", "ccc")]
list_of_name_tuples_2 = [("a", "AA"), ("b", "BBB"), ("c", "cc", "CCC")]
name_sets_1 = [set(i) for i in list_of_name_tuples_1]
name_sets_2 = [set(i) for i in list_of_name_tuples_2]

overlap = {}
for l1, s1 in zip(list_of_name_tuples_1, name_sets_1):
    d = overlap.setdefault(l1, {})
    for l2, s2 in zip(list_of_name_tuples_2, name_sets_2):
        d[l2] = len(s1 & s2)

这可以在后续代码中节省大量工作,后者代码将通过重叠[l1] [l2]而不是重叠[(l1,l2)](没有元组构造或哈希生成)来访问它,并且嵌套循环可以获取d =在外循环中重叠[l1]然后在内循环中访问d [l2].

点赞