对排序列表中的多个条目进行平均

average over multiple entries in a sorted list

我有一个排序的二维列表,其中第一列中的特定值可以出现多次,但第二列中的对应值不同。

示例:

1   10
2   20
3   30
3   35
4   40
5   45
5   50
5   55
6   60

我想对这些多个条目进行平均,以便我的最终列表看起来像

1   10
2   20
3   32.5
4   40
5   50
6   60

一个问题是,您不知道某个值出现了多少次。到目前为止我的代码看起来像

for i in range(len(list)):
    print i
    if i+1 < len(list):
        if list[i][0] == list[i+1][0]:
            j = 0
            sum = 0
            while list[i][0] == list[i+j][0]:     #this while loop is there to account for the unknown number of multiple values
                sum += list[i+j][1]
                j += 1
            avg = sum / j
            #print avg
            #i+=j                                 # here I try to skip the next j steps in the for loop, but it doesn't work
            #final[i].append(i)
            #final[i].append(avg)                 # How do I append a tuple [i, avg] to the final list?
        else:
            final.append(list[i])
    else:
        final.append(list[i])
print final

我的问题是:

您可以使用字典来计算左列中的每个值出现了多少次?和一个单独的字典来映射与每个左条目关联的元素的总和。然后用最后一个 for 循环,将总和除以计数。

from collections import defaultdict
someList = [(1,10), (2,20), (3,30), (4,40), (5,45), (5,50), (5,55)]
count_dict = defaultdict(lambda:0)
sum_dict = defaultdict(lambda:0.0)
for left_val, right_val in someList:
    count_dict[left_val] += 1
    sum_dict[left_val] += right_val

for left_val in sorted(count_dict):
    print left_val, sum_dict[left_val]/count_dict[left_val]

输出

1 10.0
2 20.0
3 30.0
4 40.0
5 50.0

首先我们需要将列组合在一起。我们将使用字典来完成此操作,其中键是左列,值是该键的值列表。然后,我们可以做一个简单的计算得到平均值。

from  collections import defaultdict

data = [
    (1, 10),
    (2, 20),
    (3, 30),
    (3, 35),
    (4, 40),
    (5, 45),
    (5, 50),
    (5, 55),
    (6, 60)
]

# Organize the data into a dict
d = defaultdict(list)
for key, value in data:
    d[key].append(value)

# Calculate the averages
averages = dict()
for key in d:
    averages[key] = sum(d[key]) / float(len(d[key]))

# Use the averages
print(averages)

输出:

{1: 10.0, 2: 20.0, 3: 32.5, 4: 40.0, 5: 50.0, 6: 60.0}

以下代码使用 itertools 中的 groupby

lst = [[1, 10],
       [2, 20],
       [3, 30],
       [3, 35],
       [4, 40],
       [5, 45],
       [5, 50],
       [5, 55],
       [6, 60],
       ]
from itertools import groupby

avglst = []
for grpname, grpvalues in groupby(lst, lambda itm: itm[0]):
    values = [itm[1] for itm in grpvalues]
    avgval = float(sum(values)) / len(values)
    avglst.append([grpname, avgval])
print(avglst)

当运行:

$ python avglist.py                                                                    (env: stack)
python[[1, 10.0], [2, 20.0], [3, 32.5], [4, 40.0], [5, 50.0], [6, 60.0]]

它提供了您要求的结果。

解释:

groupby 获取可迭代对象(列表)和一个函数,该函数计算称为键的 s,即一个值, 用于创建组。在我们的例子中,我们将根据列表项中的第一个元素进行分组。

请注意,每次键值更改时 groupby 都会创建组,因此请确保您的输入列表是 排序,否则你会得到比你预期更多的组。

groupby returns 元组 (grpname, groupvalues) 其中 grpname 是给定的键值 组,groupvalues 是该组中所有项目的迭代器。小心,它不是 list,要从中获取列表,某些东西(比如调用 list(grpvalues))必须迭代这些值。 在我们的例子中,我们使用列表推导式进行迭代,只在每个列表元素中选择第二项。

虽然 python 中的迭代器、生成器和类似结构乍一看似乎过于复杂, 他们目前的服务非常好,必须处理非常大的列表和可迭代对象。在这样一个 在这种情况下,Python 迭代器仅在内存中保存当前项,因此可以管理非常大甚至 无尽的迭代。

以下是结合使用 CounterOrderedDict 的方法:

from __future__ import division  # Python 2
from collections import Counter, OrderedDict
counts, sums = OrderedDict(), Counter()
for left, right in [(1,10), (2,20), (3,30), (4,40), (5,45), (5,50), (5,55)]:
    counts[left] = counts.get(left, 0) + 1
    sums[left] += right

result = [(key, sums[key]/counts[key]) for key in counts]