【问题标题】:Python using for loops to do a groupby is too slow, faster way?Python 使用 for 循环来做 groupby 太慢,更快的方式?
【发布时间】:2017-01-20 09:55:00
【问题描述】:

我有一个从l2 中每个元组的第一个索引中提取的唯一整数列表。

我正在尝试在元组的第一个索引(即唯一列表中的每个项目)上执行groupby in l2 之类的操作,这样我就可以计算元组的第二个索引出现的次数l2 存在于 l3 中。 - 请参阅示例。

为此,我为唯一列表中的每个项目设置了一个字典,并在每次循环后重置。 dict键是l3中的每个值。

我的代码运行良好,但当我有大量数据时,它会非常慢,因为有很多循环。

有什么方法可以提高效率和速度?

l1 = [1,2,3]
l2 = [(1,'a'),(3,'c'),(3,'b'),(2,'b'),(1,'a'),(3,'a')]
l3 = ['a','b']

d = defaultdict(int)
for i in l1:
    d = d.fromkeys(d, 0) # reset dict values to 0
    for t in l2:
        if i==t[0]:
           if t[1] in l3:
               d[t[1]] +=1
    print d

例子:

when i == 1:
d = {'a':2,'b':0}

【问题讨论】:

  • 实数是多少? l1 和 l3 具体有多大?
  • 我得到关键错误:KeyError: 'a' 可能是因为您重新创建了一个标准字典(不是默认字典)覆盖了 d。所以你的minimal reproducible example 不起作用。
  • l1 的长度可以达到 30000。L2 甚至更多,因为它并不明显

标签: python performance loops


【解决方案1】:

l3 设置为,用于快速成员资格测试。将所有基于l1的计数器放入字典中;这样你就不需要循环 l1 只需使用 t[0] 值来选择正确的计数器:

counts = {i: defaultdict(int) for i in l1}
s3 = set(l3)
for t0, t1 in l2:
    # only count if t[1] is included in l3, and t[0] is in l1
    if t1 not in s3 or t0 not in counts:
        continue
    counts[t0][t1] += 1

for d in counts.itervalues():
    print d

这会删除两个乘数; len(l1)len(l3),所以曾经的 O(NKM) 循环现在变成了 O(K) 循环。

这确实增加了内存需求,因为您现在需要跟踪 len(l1) defaultdict 对象。预先为这些对象分配内存也需要一些时间。

【讨论】:

    【解决方案2】:

    我会将 defaultdict 与 Counter 结合起来:

    >>> from collections import defaultdict, Counter
    

    然后你可以查询任何你想要的:

    >>> grouper = defaultdict(Counter)
    >>> for n, c in l2:
    ...     grouper[n][c] += 1
    ...
    >>> grouper[1]
    Counter({'a': 2})
    >>> grouper[2]
    Counter({'b': 1})
    >>> grouper[3]
    Counter({'b': 1, 'c': 1, 'a': 1})
    >>> grouper[3]['a']
    1
    >>> grouper[3]['b']
    1
    

    【讨论】:

    • 计数器在这里没有添加任何东西;除非您打算使用其他 Counter-specific 功能,否则使用 Counter 而不是 defaultdict 不是很有用。
    • 您确实需要先过滤l3。也不能保证nl1中,所以不应该计算在内。
    • 好吧,我想它可以很容易地使用defaultdict(lambda:defaultdict(int)),或者只是使用defaultdict(dict).setdefault(c,0) + 1
    • 也许我误解了这个问题:为什么需要过滤 l3
    • 但再次假设t[0] 中的所有 值都将被计算在内。 OP 只计算出现在l1 中的那些值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-07
    • 2016-01-01
    • 2020-09-09
    • 2018-07-25
    • 2022-10-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多