在Python字典中找到非零值的平均值

0 投票
3 回答
1449 浏览
提问于 2025-04-18 18:14

在这个Python字典中,最快的方法来找出非零“表”值的平均数是什么呢?

d = {"a":{"pen":12,"table":23},"b":{"pen":12,"table":0},"c":{"pen":16,"table":54}}

我想到的是:

count = sum(1 for inner_dict in d if d[inner_dict]["table"] > 0)
total = sum([d[inner_dict]["table"] for inner_dict in d if d[inner_dict]["table"] > 0])
average = total/count

结果应该是(23+54)/2 = 38

3 个回答

2

只循环一次:

n, s = reduce(lambda acc,v: (acc[0]+1,acc[1]+v["table"]) if v["table"] else acc,
              d.values(),
              (0.,0.))
print n, s, s/n

产生:

2.0 77.0 38.5
3

因为你问的是最快的方式,这里有一些时间测试的结果。需要说明的是,我是在Windows 8上使用IPython和Python 3.3,运行的是i7-3770处理器。另外,顺便提一下,在Python 2.x中不要用/来做除法,因为那样会进行整数除法。可以用float(a)/b,或者在文件顶部加上from __future__ import division

d = {"a": {"pen": 12, "table": 23}, 
     "b": {"pen": 12, "table": 0},
     "c": {"pen": 16, "table": 54}}

def method0():  # Your method
    count = sum(1 for inner_dict in d if d[inner_dict]["table"] > 0)
    total = sum([d[inner_dict]["table"] for inner_dict in d if d[inner_dict]["table"] > 0])
    average = total/count

def method1():
    count = 0
    total = 0
    for a in d.values():
        val = a['table']
        if val > 0:
            count += 1
            total += val
    average = total/ count

def method2():  # user3684792's/Padraic Cunningham's method
    filtered = [d[i]["table"] for i in d if d[i]["table"] > 0]
    average = sum(filtered)/len(filtered)   

# from functools import reduce  # If using Python 3
def method3():  # Sylvain Leroux's method
    n, s = reduce(lambda acc,v: (acc[0]+1,acc[1]+v["table"]) if v["table"] else acc,
                  d.values(),
                  (0, 0))
    average = s/n


%timeit method0()
# 10000 loops, best of 3: 23.9 us per loop

%timeit method1()
# 1000000 loops, best of 3: 756 ns per loop

%timeit method2()
# 10000 loops, best of 3: 22.5 us per loop

%timeit method3()
# 1000000 loops, best of 3: 1.29 us per loop

初步结论:使用for循环和简单的加法(method1)比任何列表推导的方法都要快。

这基本上是你可以预期的结果。注意,方法1和方法3只遍历数据一次,边走边收集数据。而方法0和方法2则需要多遍历几次,先过滤出想要的条目,然后再进行求和。

3
filtered = [d[i]["table"] for i in d if d[i]["table"]<>0]
avg = sum(filtered)/len(filtered)

其实不需要 <>0 这个东西。

撰写回答