最快的方法是在python中按键添加一个dicts列表

时间:2009-08-19 16:38:40

标签: python dictionary

说我有一堆词典

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

那里只有两个,但问题是关于仲裁金额。

找到每个密钥的平均值的最快方法是什么?这些词汇非常稀疏,因此很多情况下会有很多键不存在。

我正在寻找的结果是一个新词典,其中包含所有键和每个键的平均值。值总是漂浮,我很乐意深入到ctypes。我的方法比我想要的慢,可能是因为在我的情况下我使用默认值,这意味着即使它们不存在,我实际上也在初始化值。如果这是缓慢的原因我很乐意重构,只是想确保我没有遗漏任何明显的东西。

编辑:我认为我误导了结果应该是什么,如果值不存在它应该作为0.0,所以上面例子的结果将是:

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

因此除法是唯一键的总数。

我想知道的主要问题是,是否有一种偷偷摸摸的方式将整个字典分成一个长度,或者一步完成。基本上是一个非常快速的向量加法和除法。我简要介绍了numpy数组,但它们似乎不适用于dicts,如果我将dicts转换为list,我必须删除稀疏属性(通过明确地将缺少的值设置为0)。

6 个答案:

答案 0 :(得分: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(),当您看到新值时,会比计算平均值获得一些性能,但我确实错了。

答案 1 :(得分: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程序中的时间瓶颈在内存分配器中,使用较少的内存可以提高速度。

答案 2 :(得分: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]))
    

答案 3 :(得分:0)

您的瓶颈可能是由于过多的内存使用造成的。考虑使用iteritems来利用生成器的能力。

由于您说数据稀疏,因此可能效率最低。考虑迭代器的这种替代用法:

dicts = ... #Assume this is your dataset
totals = {}
lengths = {}
means = {}
for d in dicts:
    for key,value in d.iteritems():
        totals.setdefault(key,0)
        lengths.setdefault(key,0)
        totals[key] += value
        length[key] += 1
for key,value in totals.iteritems():
    means[key] = value / lengths[key]

此处总计,长度和均值是您创建的唯一数据结构。这应该是相当快速的,因为它避免了必须创建辅助列表,并且每个字典只包含每个字典一次。

这是第二种方法,我怀疑它会比第一种方法有所改善,但从理论上讲,它可能会取决于您的数据和机器,因为它需要更少的内存分配:

dicts = ... #Assume this is your dataset
key_set = Set([])
for d in dicts: key_set.update(d.keys())
means = {}
def get_total(dicts, key):
    vals = (dict[key] for dict in dicts if dict.has_key(key))
    return sum(vals)
def get_length(dicts, key):
    vals = (1 for dict in dicts if dict.has_key(key))
    return sum(vals)
def get_mean(dicts,key):
    return get_total(dicts,key)/get_length(dicts,key)
for key in key_set:
    means[key] = get_mean(dicts,key)

您最终会为每个键循环遍历所有字典两次,但除了key_set之外,不需要任何中间数据结构。

答案 4 :(得分:0)

scipy.sparse支持稀疏矩阵 - dok_matrix形式似乎非常适合您的需求(但您必须使用整数坐标,因此需要单独传递以收集和放入任意但确定的顺序你现在拥有的字符串键)。如果你有大量非常庞大且稀疏的“阵列”,性能提升可能是值得的复杂。

答案 5 :(得分:0)

这很简单,但这可行:

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

ds = [a, b]
result = {}

for d in ds:
    for k, v in d.iteritems():
        result[k] = v + result.get(k, 0)

n = len(ds)
result = dict((k, amt/n) for k, amt in result.iteritems())

print result

我不知道它与你的方法相比如何,因为你没有发布任何代码。