从字典列表中优化平均值计算

3

我有一个字典列表,包含键'a','n','o','u'。 是否有办法加速这个计算,比如使用NumPy?列表中有数万个项目。

数据是从数据库获取的,所以我必须处理原始的字典列表形式。

x = n = o = u = 0
for entry in indata:
    x += (entry['a']) * entry['n']  # n - number of data points
    n += entry['n']
    o += entry['o']
    u += entry['u']

    loops += 1

average = int(round(x / n)), n, o, u

1
这段代码的目的是什么?周围的代码是什么?上下文很重要。 - John Kugelman
@JohnKugelman,稍微更新了一下问题。 - Prof. Falken
你可以尝试使用 operator.itemgetter 进行优化。 - mgilson
3
也许你的数据库可以对这些数值求和。 - Jochen Ritzel
@mgilson,写一个如何做到这一点的示例,并获得点赞。 :) - Prof. Falken
3个回答

3

我怀疑这样做不会更快,但我认为它是timeit的一个备选项...

from operator import itemgetter
x = n = o = u = 0
items = itemgetter('a','n','o','u')
for entry in indata:
    A,N,O,U = items(entry)
    x += A*N  # n - number of data points
    n += N
    o += O    #don't know what you're doing with O or U, but I'll leave them
    u += U

average = int(round(x / n)), n, o, u

至少这样做可以避免查找entry['n']的过程,因为我已经将其保存到变量中了。


2
@AmigableClarkKant -- 我觉得当我可以一次从dict中使用itemgetter获取多个值时,这很酷。我以前从未尝试过这样做 - 所以我想分享一下。也许在某个时候,我会进行一个快速的timeit测试来查看它的性能... - mgilson
是的。顺便说一下,我在我的数据上对你的代码进行了分析,似乎快了约10%。 :-) - Prof. Falken
现在看起来更漂亮了,我想我会使用你的版本。更快和更漂亮是一个净胜利。 - Prof. Falken

2
您可以尝试像这样做:


mean_a = np.sum(np.array([d['a'] for d in data]) * np.array([d['n'] for d in data])) / len(data)

编辑:实际上,@mgilson的上述方法更快:


import numpy as np
from operator import itemgetter
from pandas import *

数据=[] 对于i在range(100000)中: 数据.append({'a':np.random.random(), 'n':np.random.random(), 'o':np.random.random(), 'u':np.random.random()})

def func1(数据): x = n = o = u = 0 items = itemgetter('a','n','o','u') for entry in 数据: A,N,O,U = items(entry) x += A*N # n - 数据点数 n += N o += O #不知道你在做什么O和U,但我会保留它们 u += U

    average = int(round(x / n)), n, o, u
    return average

def func2(data): mean_a = np.sum(np.array([d['a'] for d in data]) * np.array([d['n'] for d in data]))/len(data) return (mean_a, np.sum([d['n'] for d in data]), np.sum([d['o'] for d in data]), np.sum([d['u'] for d in data]) )

def func3(data): dframe = DataFrame(data) return np.sum((dframe["a"]*dframe["n"])) / dframe.shape[0], np.sum(dframe["n"]), np.sum(dframe["o"]), np.sum(dframe["u"])

In [3]: %timeit func1(data) 10次循环,最好的结果:每个循环花费59.6毫秒

In [4]: %timeit func2(data) 10次循环,最好的结果:每个循环花费138毫秒

In [5]: %timeit func3(data) 10次循环,最好的结果:每个循环花费129毫秒

如果您正在对数据进行其他操作,我肯定会建议使用Pandas包。它的DataFrame对象非常适合与您正在使用的字典列表匹配。我认为大部分开销是将数据读取到numpy数组或DataFrame对象中的IO操作。


1
我简直不敢相信itemgetter能够击败numpy。我想这里的瓶颈确实是将数据从字典中取出并转换为numpy所需的形式。 - mgilson
1
是的。我很震惊。我认为肯定是IO进入numpy数组导致了瓶颈。 - reptilicus
1
我不一定会在这里使用“IO”这个术语,但你是对的。(通常我认为IO是指读写磁盘——但你已经提前构建了列表)。 - mgilson
@mgilson,也许可以称之为“内存瓶颈”或其他类似的名称。 - Prof. Falken

0

如果你只是想得到某个东西的平均值,为什么不

sum_for_average = math.fsum(your_item)
average_of_list = sum_for_average / len(your_item)

完全不需要在numpy上瞎搞。


如何将字典列表转换为“your_list”? - Prof. Falken
如果你有一个字典条目是一组数字,那么数学模块中有几个函数可以为你提供帮助。在代码中,使用“你的列表”作为通用占位符文本。 - Jiynx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接