Усредните дублированные значения из двух парных списков в Python - PullRequest
3 голосов
/ 26 октября 2010

в моем коде я получаю два разных списка из разных источников, но я знаю, что они в одном порядке. Первый список («names») содержит список строк ключей, а второй («result_values») представляет собой последовательность чисел с плавающей точкой. Мне нужно сделать пару уникальной, но я не могу использовать словарь, так как будет сохранено только последнее введенное значение: вместо этого мне нужно сделать среднее (среднее арифметическое) значений, имеющих дублирующий ключ.

Пример желаемых результатов:

names = ["pears", "apples", "pears", "bananas", "pears"]
result_values = [2, 1, 4, 8, 6] # ints here but it's the same conceptually

combined_result = average_duplicates(names, result_values)

print combined_result

{"pears": 4, "apples": 1, "bananas": 8}

Мои единственные идеи включают в себя несколько итераций и до сих пор были уродливы ... есть ли элегантное решение этой проблемы?

Ответы [ 5 ]

5 голосов
/ 26 октября 2010
from collections import defaultdict
def averages(names, values):
    # Group the items by name.
    value_lists = defaultdict(list)
    for name, value in zip(names, values):
        value_lists[name].append(value)

    # Take the average of each list.
    result = {}
    for name, values in value_lists.iteritems():
        result[name] = sum(values) / float(len(values))
    return result

names = ["pears", "apples", "pears", "bananas", "pears"]
result_values = [2, 1, 4, 8, 6]
print averages(names, result_values)
3 голосов
/ 26 октября 2010

Вы можете рассчитать среднее значение, используя Совокупное скользящее среднее , чтобы выполнить итерацию по спискам только один раз:

from collections import defaultdict
averages = defaultdict(float)
count = defaultdict(int)

for name,result in zip(names,result_values):
    count[name] += 1
    averages[name] += (result - averages[name]) / count[name]
3 голосов
/ 26 октября 2010

Я бы в любом случае использовал словарь

averages = {}
counts = {}
for name, value in zip(names, result_values):
    if name in averages:
        averages[name] += value
        counts[name] += 1
    else:
        averages[name] = value
        counts[name] = 1
for name in averages:
    averages[name] = averages[name]/float(counts[name]) 

Если вас интересуют большие списки, я бы заменил zip на izip из itertools.

1 голос
/ 26 октября 2010

Я думаю, что вы ищете itertools.groupby:

import itertools

def average_duplicates(names, values):
  pairs = sorted(zip(names, values))
  result = {}
  for key, group in itertools.groupby(pairs, key=lambda p: p[0]):
    group_values = [value for (_, value) in group]
    result[key] = sum(group_values) / len(group_values)
  return result

См. Также zip и sorted.

0 голосов
/ 26 октября 2010
>>> def avg_list(keys, values):
...     def avg(series):
...             return sum(series) / len(series)
...     from collections import defaultdict
...     d = defaultdict(list)
...     for k, v in zip(keys, values):
...             d[k].append(v)
...     return dict((k, avg(v)) for k, v in d.iteritems())
... 
>>> if __name__ == '__main__':
...     names = ["pears", "apples", "pears", "bananas", "pears"]
...     result_values = [2, 1, 4, 8, 6]
...     print avg_list(names, result_values)
... 
{'apples': 1, 'pears': 4, 'bananas': 8}

Вы можете получить avg() return float(len(series)), если хотите получить среднее значение с плавающей запятой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...