如何在Python字典中对相同键的值进行平均?

3
我可以帮您翻译成中文。以下是需要翻译的内容:

我有一个包含多个字典的列表,使用Python语言。

[{"country": "IE", "values": ["Server1-17.6650", "Server3-78.6064", "Server2-3.7286"]}, {"country": "CA", "values": ["Server1-100.0000"]}, {"country": "DE", "values": ["Server2-100.0000"]}, {"country": "JP", "values": ["Server2-100.0000"]}, {"country": "IT", "values": ["Server1-100.0000"]}, {"country": "US", "values": ["Server1-6.3158", "Server3-15.7895", "Server2-77.8947", "Server1-5.5556", "Server3-2.7778", "Server2-91.6667", "Server1-12.6145", "Server3-86.8043", "Server2-0.5811"]}, {"country": "CZ", "values": ["Server1-100.0000"]}, {"country": None, "values": ["Server1-100.0000", "Server2-100.0000", "Server2-100.0000", "Server1-100.0000"]}, {"country": "A", "values": ["Server2-100.0000"]}, {"country": "IL", "values": ["Server1-100.0000"]}, {"country": "BR", "values": ["Server2-100.0000"]}, {"country": "KP", "values": ["Server1-100.0000"]}, {"country": "SG", "values": ["Server1-79.2000", "Server2-20.8000"]}, {"country": "ES", "values": ["Server1-100.0000"]}]

现在对于每个 values,如果服务器名称在列表中重复,则必须在服务器后的 - 值上取平均值。 对于上面的列表,最终输出如下。

[{"country": "IE", "values": ["Server1-17.6650", "Server3-78.6064", "Server2-3.7286"]}, {"country": "CA", "values": ["Server1-100.0000"]}, {"country": "DE", "values": ["Server2-100.0000"]}, {"country": "JP", "values": ["Server2-100.0000"]}, {"country": "IT", "values": ["Server1-100.0000"]}, {"country": "US", "values": ["Server1-8.1619", "Server3-35.1238", "Server2-56.7141"]}, {"country": "CZ", "values": ["Server1-100.0000"]}, {"country": None, "values": ["Server1-100.0000", "Server2-100.0000", "Server2-100.0000", "Server1-100.0000"]}, {"country": "AU", "values": ["Server2-100.0000"]}, {"country": "IL", "values": ["Server1-100.0000"]}, {"country": "BR", "values": ["Server2-100.0000"]}, {"country": "KP", "values": ["Server1-100.0000"]}, {"country": "SG", "values": ["Server1-79.2000", "Server2-20.8000"]}, {"country": "ES", "values": ["Server1-100.0000"]}] 

我用Python尝试了下面的代码。
for key_dict in resp:
    for i, value in enumerate(key_dict['values']):
        for j, new_value in enumerate(key_dict['values']):
            if value[:value.index('-')] == new_value[:new_value.index('-')]:
                key_dict['values'][i] = value[:value.index('-')] + str(float(value[value.index('-'):]) + float(new_value[new_value.index('-'):]))
                del key_dict['values'][j]

但这并不能产生我所需的结果。有没有人能指出如何在Python中实现这一点。


4
你是否可以掌控数据结构?把“values”改为一个字典,其中包含服务器名称及其对应的数值,这样会更加合理。 - SuperBiasedMan
你是全部给这三个答案投了反对票,还是有其他人无缘无故地这么做了?因为我可以理解有人真正为mescalinum的回答投了反对票(它没有解释,实际上只是用一种混淆的方式执行我的答案中的最后一个版本),但我无法想象为什么会有人对ohruunuruus的回答投反对票。 - abarnert
不,我没有在这里给任何答案点踩。 - station
2个回答

5
这是一个如果使用正确的数据结构就很简单,否则就很麻烦的问题。如果values是一个将服务器名称映射到数字列表的字典,而不是一个大字符串列表,那么这个问题就很容易解决:
如果您可以控制值的初始获取方式,那么您应该这样做。如果不能,您可能需要手动转换它们。像这样:
for key_dict in resp:
    new_values = {}
    for value in key_dict['values']:
        name, number = value.split('-', 1)
        new_values.setdefault(name, []).append(float(number))
    key_dict['values'] = new_values

现在,将它们平均化就很简单了:

for key_dict in resp:
    averages = {}
    for name, numbers in key_dict['values'].items():
        averages[name] = sum(numbers) / len(numbers)
    key_dict['values'] = averages

如果你真的需要在最后将它转换回字符串,你可以这样做:

for key_dict in resp:
    key_dict['values'] = ['{}-{}'.format(name, value) 
                          for name, value in key_dict['values'].items()]

当然,如果你真的想的话,你可以将所有内容都内联起来:
for key_dict in resp:
    values = {}
    for value in key_dict['values']:
        name, number = value.split('-', 1)
        values.setdefault(name, []).append(float(number))
    values = ['{}-{}'.format(name, sum(numbers)/len(numbers))
              for name, numbers in values.items()]
    key_dict['values'] = values

你能帮我吗?如果我想除以列表的最大长度,而不是 len(numbers),这样我的值实际上会加到100。上面的解决方案导致拆分总和超过100。 - station
@user567797:要获取字典 d 中列表的最大长度,可以使用 max(d.values(), key=len) 来返回具有最长长度的列表,然后使用 len(that) 来获取该列表的长度。这是你想要的吗? - abarnert
@user567797:好的,如果你想要计算所有列表的长度之和,你可以使用sum函数而不是max函数:sum(len(v) for v in d.values()) - abarnert

2
您可以在这里使用groupby
import numpy as np
from itertools import groupby

def average_servers(server_list):

    post_split = [x.split('-') for x in server_list]
    averages = []

    for server, data in groupby(sorted(post_split), lambda x: x[0]):

         cur_average = np.mean([float(x[1]) for x in list(data)])
         averages.append('{}-{}'.format(server, cur_average))

    return averages

然后应用该函数生成一个新的字符串列表作为values键的值:

for entry in your_data_structure:
    entry['values'] = average_servers(entry['values'])

几分钟前,有人将所有三个答案都点了踩,但没有给出任何解释。不知道为什么。 - abarnert

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