【问题标题】:Average of all elements in tuple list having the same index元组列表中具有相同索引的所有元素的平均值
【发布时间】:2020-11-10 13:19:28
【问题描述】:

我有一个非常奇怪的数据结构,它是一个元组列表。每个元组有五个元素,其中第一个是标识字符串,其他四个是浮点数字符串(很奇怪,它们不仅仅是浮点数)。 抱歉,我从其他人那里得到了这些数据。

我想对第一个索引相同的 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 循环来提取所有内容?

【问题讨论】:

  • 是的,但很可能是 pandas 而不是 numpy - 添加了标签以便那些向导可以提供帮助。
  • 如果没有列出,也可能是结构化数组。

标签: python pandas numpy average


【解决方案1】:

可以先创建一个dict来收集每个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) 可以让我们简单地为每个键附加新的值列表,因为如果该列表尚不存在,则会自动创建一个空列表。

【讨论】:

  • @PatrickArtner 哎呀...我误读了这个问题...谢谢,我会编辑它!
  • 你太棒了!它工作得很好,也谢谢你的解释。我没想到这个奇怪的问题会有这么好的和快速的答案。
  • "out = [(id, *[str(mean(column)) for column in zip(*values)]) for id, values in d.items()]" 将为您提供你想要的输出格式
【解决方案2】:

一些数字争吵:

  • 使用正确的键和实际浮点数的列表创建一个 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]})

【讨论】:

  • 也感谢您出色而快速的回答。 :)
【解决方案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)]

【讨论】:

    【解决方案4】:

    有了 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
    

    【讨论】:

    • 非常感谢!这也是一个非常好的可读解决方案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-23
    • 2021-06-25
    • 2022-11-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多