元组列表中相同索引的所有元素的平均值

3

我有一种非常奇特的数据结构,它是一个元组列表。每个元组有五个元素,第一个元素是一个标识字符串,其余四个元素都是浮点数字符串(很奇怪,它们不是普通的浮点数)。 抱歉,这些数据是从别人那里获取的。

我想要对所有具有相同第一个索引的2-5数字求平均值。 例如:

   [('ch', ' 0.8307', '0.8583', '0.8047', ' 0.969'),
    ('de', ' 0.721', '0.7529', '0.6917', ' 0.968'),
    ('en', ' 0.8441', '0.8732', '0.8168', ' 0.9569'),
    ('fn', ' 0.8207', '0.8574', '0.7870', ' 0.9609'),
    ('ch', ' 0.466', '0.572', '0.7733', ' 0.969'),
    ('de', ' 0.322', '0.385', '0.5431', ' 0.968'),
    ('sp', ' 0.7609', '0.7893', '0.7344', ' 0.9663'),
    ('ti', ' 0.8135', '0.8430', '0.7860', ' 0.9662')]

输出应该将所有具有相同第一个索引的元素收缩在一起,并平均它们的值,因此它将类似于(我在此处的示例输出中没有对值进行平均):
   [('ch', ' 0.8307', '0.8583', '0.8047', ' 0.969'),
    ('de', ' 0.721', '0.7529', '0.6917', ' 0.968'),
    ('en', ' 0.8441', '0.8732', '0.8168', ' 0.9569'),
    ('fn', ' 0.8207', '0.8574', '0.7870', ' 0.9609'),
    ('sp', ' 0.7609', '0.7893', '0.7344', ' 0.9663'),
    ('ti', ' 0.8135', '0.8430', '0.7860', ' 0.9662')]

我能否在这里做些非常聪明的事情,而不是制作一个巨大的for循环来提取所有内容?


1
是的,但很可能是pandas而不是numpy - 添加了标签以便那些专家能够帮助。 - Daniel F
如果不是列表,它也可能是一个结构化数组。 - mathfux
4个回答

5

您可以先创建一个字典来收集与每个id相关的所有值,然后计算平均值:

from collections import defaultdict

data = [('ch', ' 0.8307', '0.8583', '0.8047', ' 0.969'),
('de', ' 0.721', '0.7529', '0.6917', ' 0.968'),
('en', ' 0.8441', '0.8732', '0.8168', ' 0.9569'),
('fn', ' 0.8207', '0.8574', '0.7870', ' 0.9609'),
('ch', ' 0.466', '0.572', '0.7733', ' 0.969'),
('de', ' 0.322', '0.385', '0.5431', ' 0.968'),
('sp', ' 0.7609', '0.7893', '0.7344', ' 0.9663'),
('ti', ' 0.8135', '0.8430', '0.7860', ' 0.9662')]

def mean(lst):
    return sum(lst)/len(lst)

d = defaultdict(list)
for id, *values in data:
    d[id].append(list(map(float, values)))

    
    
out = {id: [mean(column) for column in zip(*values)] for id, values in d.items() }
    
    
print(out)

    # {'ch': [0.64835, 0.71515, 0.7889999999999999, 0.969], 
    #  'de': [0.5215, 0.5689500000000001, 0.6174, 0.968],
    #  'en': [0.8441, 0.8732, 0.8168, 0.9569], 
    #  'fn': [0.8207, 0.8574, 0.787, 0.9609], 
    #  'sp': [0.7609, 0.7893, 0.7344, 0.9663], 
    #  'ti': [0.8135, 0.843, 0.786, 0.9662]}

for id, *values in data: 中,我们遍历 data 元组列表,并将元组的第一项放入id,其余值放入values
此外,使用 defaultdict(list) 使我们可以简单地将每个键的新值列表附加到末尾,因为如果列表不存在,则会自动创建一个空列表。

1
@PatrickArtner 哎呀...我看错了问题...谢谢,我会修改的! - Thierry Lathuille
你太棒了!它运行得非常好,谢谢你的解释。我没有想到对于那个奇怪的问题会有这么好和快速的回答。 - Hemmelig
"out = [(id, *[str(mean(column)) for column in zip(*values)]) for id, values in d.items()]" 这行代码将会按照您所期望的格式输出结果。 - Muhammed B. Aydemir

4

一些数字处理:

  • 使用正确的键和包含实际浮点数的列表创建defaultdict
  • 检查是否需要平均,并利用zip()函数进行平均

data = [('ch', ' 0.8307', '0.8583', '0.8047', ' 0.969'),
    ('de', ' 0.721', '0.7529', '0.6917', ' 0.968'),
    ('en', ' 0.8441', '0.8732', '0.8168', ' 0.9569'),
    ('fn', ' 0.8207', '0.8574', '0.7870', ' 0.9609'),
    ('ch', ' 0.466', '0.572', '0.7733', ' 0.969'),
    ('de', ' 0.322', '0.385', '0.5431', ' 0.968'),
    ('sp', ' 0.7609', '0.7893', '0.7344', ' 0.9663'),
    ('ti', ' 0.8135', '0.8430', '0.7860', ' 0.9662')]

from pprint import pprint
from collections import defaultdict 
d = defaultdict(list)

for t in data:
    d[t[0]].append(list(map(float, t[1:])))

pprint(d)

for key, values in d.items():
    w = len(values)
    if w > 1:
        d[key] = [sum(numbers) / w for numbers in zip(*values)]
    else:
        d[key] = d[key][0]

pprint(d)

输出:

# after converting to float and collecting into lists
defaultdict(<class 'list'>,
            {'ch': [[0.8307, 0.8583, 0.8047, 0.969],
                    [0.466, 0.572, 0.7733, 0.969]],
            'de': [[0.721, 0.7529, 0.6917, 0.968],
                    [0.322, 0.385, 0.5431, 0.968]],
            'en': [[0.8441, 0.8732, 0.8168, 0.9569]],
            'fn': [[0.8207, 0.8574, 0.787, 0.9609]],
            'sp': [[0.7609, 0.7893, 0.7344, 0.9663]],
            'ti': [[0.8135, 0.843, 0.786, 0.9662]]})

# after averaging
defaultdict(<class 'list'>,
            {'ch': [0.64835, 0.71515, 0.7889999999999999, 0.969],
            'de': [0.5215, 0.5689500000000001, 0.6174, 0.968],
            'en': [0.8441, 0.8732, 0.8168, 0.9569],
            'fn': [0.8207, 0.8574, 0.787, 0.9609],
            'sp': [0.7609, 0.7893, 0.7344, 0.9663],
            'ti': [0.8135, 0.843, 0.786, 0.9662]})

1
谢谢你的惊人和快速回答。 :) - Hemmelig

3

使用Pandas更加简单:

data = [('ch', ' 0.8307', '0.8583', '0.8047', ' 0.969'),
        ('de', ' 0.721', '0.7529', '0.6917', ' 0.968'),
        ('en', ' 0.8441', '0.8732', '0.8168', ' 0.9569'),
        ('fn', ' 0.8207', '0.8574', '0.7870', ' 0.9609'),
        ('ch', ' 0.466', '0.572', '0.7733', ' 0.969'),
        ('de', ' 0.322', '0.385', '0.5431', ' 0.968'),
        ('sp', ' 0.7609', '0.7893', '0.7344', ' 0.9663'),
        ('ti', ' 0.8135', '0.8430', '0.7860', ' 0.9662')]

import pandas as pd

df = pd.DataFrame(data, dtype=float)

print(df.groupby(0).mean())

输出:

          1        2       3       4
0
ch  0.64835  0.71515  0.7890  0.9690         # pandas displays "nice" numbers,
de  0.52150  0.56895  0.6174  0.9680         # it contains the "correct" ones
en  0.84410  0.87320  0.8168  0.9569
fn  0.82070  0.85740  0.7870  0.9609
sp  0.76090  0.78930  0.7344  0.9663
ti  0.81350  0.84300  0.7860  0.9662

非常感谢!这也是一个非常好的易读解决方案。 - Hemmelig

3

类似以下的解决方案(零导入方式)

avg_data = {}
data = [('ch', ' 0.8307', '0.8583', '0.8047', ' 0.969'),
        ('de', ' 0.721', '0.7529', '0.6917', ' 0.968'),
        ('en', ' 0.8441', '0.8732', '0.8168', ' 0.9569'),
        ('fn', ' 0.8207', '0.8574', '0.7870', ' 0.9609'),
        ('ch', ' 0.466', '0.572', '0.7733', ' 0.969'),
        ('de', ' 0.322', '0.385', '0.5431', ' 0.968'),
        ('sp', ' 0.7609', '0.7893', '0.7344', ' 0.9663'),
        ('ti', ' 0.8135', '0.8430', '0.7860', ' 0.9662')]

for entry in data:
    if entry[0] not in avg_data:
        avg_data[entry[0]] = [0, [0, 0, 0, 0]]
    for idx, x in enumerate(entry[1:]):
        avg_data[entry[0]][1][idx] += float(x)
    avg_data[entry[0]][0] += 1
result = []
for k, v in avg_data.items():
    result.append([k])
    result[-1].extend([x / v[0] for x in v[1]])
    result[-1] = tuple(result[-1])
print(result)

输出

[('ch', 0.64835, 0.71515, 0.7889999999999999, 0.969), ('de', 0.5215, 0.5689500000000001, 0.6174, 0.968), ('en', 0.8441, 0.8732, 0.8168, 0.9569), ('fn', 0.8207, 0.8574, 0.787, 0.9609), ('sp', 0.7609, 0.7893, 0.7344, 0.9663), ('ti', 0.8135, 0.843, 0.786, 0.9662)]

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