在python中以最快的方式按键添加dict列表
假设我有一堆字典在python中以最快的方式按键添加dict列表,python,dictionary,Python,Dictionary,假设我有一堆字典 a = {'x': 1.0, 'y': 0.5, 'z': 0.25 } b = {'w': 0.5, 'x': 0.2 } 那里只有两个,但问题是关于一个任意的数额 找到每个键的平均值的最快方法是什么?dict非常稀疏,因此在很多情况下,各种dict中都不存在很多键 我正在寻找的结果是一个新的字典,它有所有的键和每个键的平均值。值总是浮动的,我很乐意使用ctypes。我使用的方法比我想要的慢,可能是因为在我的例子中,我使用的是defaultdicts,这意味着我实际上在初始
a = {'x': 1.0, 'y': 0.5, 'z': 0.25 }
b = {'w': 0.5, 'x': 0.2 }
那里只有两个,但问题是关于一个任意的数额
找到每个键的平均值的最快方法是什么?dict非常稀疏,因此在很多情况下,各种dict中都不存在很多键
我正在寻找的结果是一个新的字典,它有所有的键和每个键的平均值。值总是浮动的,我很乐意使用ctypes。我使用的方法比我想要的慢,可能是因为在我的例子中,我使用的是defaultdicts,这意味着我实际上在初始化值,即使它们不存在。如果这是我很乐意重构的缓慢的原因,我只想确保我没有遗漏任何明显的东西
编辑:我认为我误导了结果应该是什么,如果该值不存在,它应该作为0.0,因此上面示例的结果应该是:
{'w':0.25,'x':0.6,'y':0.25,'z':0.125}
因此,分区是由唯一键的总数决定的
我想知道的主要问题是,是否有一种偷偷摸摸的方法,可以在一步中将整个dict除以长度,或者在一步中进行加法。基本上是一个非常快速的向量加法和除法。我简要介绍了numpy数组,但它们似乎不适用于DICT,如果我将DICT转换为列表,则必须删除稀疏属性(通过显式地将缺席值设置为0)。通过分析可以证明,这不是最快的,但
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()
将在计算新值时获得一些性能,但我肯定会错的。这是有效的:
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}
我试图在tally中避免再次存储所有值,只是简单地累积最后计算平均值所需的总和和计数。通常,Python程序的时间瓶颈在内存分配器中,使用更少的内存可以大大提高速度
>>> 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}
说明:
set(sum((h.keys() for h in hashes), []))
(k, avg([h.get(k) or 0 for h in hashes]))
您的瓶颈可能是由于内存使用过多造成的。考虑使用迭代项来利用生成器的功率。< /P> 因为你说你的数据是稀疏的,这可能不是最有效的。考虑迭代器的交替用法:
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)
每个键在所有字典中循环两次,但除了键集之外,不需要中间数据结构。支持稀疏矩阵——该表单似乎非常适合您的需要(不过,您必须使用整数坐标,因此需要单独的过程来收集并以任意但明确的顺序放置您当前拥有的字符串键)。如果您有大量非常大且稀疏的“数组”,那么性能的提高可能值得复杂化。这很简单,但可以做到:
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
我不知道它与您的方法相比如何,因为您没有发布任何代码。使用
项不是无
而不是项!=无
,这要快得多。我编辑了问题以澄清结果应该是什么be@balpha:你能解释一下区别吗?@Otto Allmendinger:看这两个问题:我编辑了为了澄清结果应该是什么,我正在调查哪种方法对我来说性能最好,这要感谢到目前为止回答问题的人。