在Python中按键快速合并字典列表的方法

3 投票
6 回答
2053 浏览
提问于 2025-04-15 13:42

假设我有一堆字典。

a = {'x': 1.0, 'y': 0.5, 'z': 0.25 }
b = {'w': 0.5, 'x': 0.2 }

这里面只有两个字典,但我想讨论的是任意数量的字典。

我想知道,最快的办法是什么,来计算每个键的平均值。这些字典的内容比较稀疏,所以很多键在不同的字典里可能并不存在。

我想要的结果是一个新的字典,里面包含所有的键和每个键的平均值。值总是浮点数,我愿意使用ctypes。如果我现在的方法比较慢,可能是因为我在用defaultdict,这样即使某些值不存在,我也会初始化它们。如果这是导致慢的原因,我愿意重新考虑我的方法,只是想确保我没有忽略什么明显的东西。

编辑:我觉得我之前说得不太清楚,结果应该是,如果某个值不存在,就当作0.0,所以上面的例子结果应该是:

{'w':0.25,'x':0.6,'y':0.25,'z':0.125}

所以除法是用唯一键的总数来计算的。

我主要想知道有没有什么巧妙的方法,可以一步到位地对整个字典进行除法,或者一步到位地进行加法。简单来说,就是非常快速的向量加法和除法。我简单看了一下numpy数组,但它们似乎不适用于字典,如果我把字典转换成列表,就得把缺失的值显式设置为0,这样就失去了稀疏性。

6 个回答

1
>>> def avg(items):
...     return sum(items) / len(items)
... 
>>> hashes = [a, b]
>>> dict([(k, avg([h.get(k) or 0 for h in hashes])) for k in set(sum((h.keys() for h in hashes), []))])
{'y': 0.25, 'x': 0.59999999999999998, 'z': 0.125, 'w': 0.25}

解释:

  1. 所有哈希表中的键的集合,不重复。

    set(sum((h.keys() for h in hashes), []))
    
  2. 对于上面集合中的每个键,计算它们的平均值。如果某个哈希表中没有这个键,就用0来代替。

    (k, avg([h.get(k) or 0 for h in hashes]))
    
2

通过性能分析可能会证明,这并不是最快的方式,但...

import collections

a = {'x': 1.0, 'y': 0.5, 'z': 0.25 }
b = {'w': 0.5, 'x': 0.2 }
dicts = [a,b]

totals = collections.defaultdict(list)
avg = {}

for D in dicts:
    for key,value in D.iteritems():
        totals[key].append(value)

for key,values in totals.iteritems():
   avg[key] = sum(values) / len(values)

我在这里猜测,让Python使用内置的 sum()len() 函数,可能会在你看到新值时提高计算平均值的速度,不过我也可能错了。

2

这个方法可以用:

import collections

data= [
    {'x': 1.0, 'y': 0.5, 'z': 0.25 },
    {'w': 0.5, 'x': 0.2 }
    ]

tally = collections.defaultdict(lambda: (0.0, 0))

for d in data:
    for k,v in d.items():
        sum, count = tally[k]
        tally[k] = (sum+v, count+1)

results = {}
for k, v in tally.items():
    t = tally[k]
    results[k] = t[0]/t[1]

print results

我不知道这个方法是否比你的快,因为你没有分享你的代码。

{'y': 0.5, 'x': 0.59999999999999998, 'z': 0.25, 'w': 0.5}

我尝试在计算时只记录总和和数量,这样就不需要再存储所有的值,最后再计算平均值。通常,在Python程序中,速度慢的原因是内存分配器的问题,减少内存的使用可以大大提高速度。

撰写回答