Promedio de los valores duplicados de dos listas emparejadas en Python

En mi código obtengo dos listas diferentes de diferentes fonts, pero sé que están en el mismo orden. La primera lista (“nombres”) contiene una lista de cadenas de claves, mientras que la segunda (“valores de resultado”) es una serie de flotadores. Necesito hacer que el par sea único, pero no puedo usar un diccionario porque solo se mantendría el último valor insertado: en cambio, necesito hacer un promedio (media aritmética) de los valores que tienen una clave duplicada.

Ejemplo de los resultados deseados:

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} 

Mis únicas ideas involucran múltiples iteraciones y hasta ahora han sido feas … ¿existe una solución elegante para este problema?

Yo usaría un diccionario de todos modos

 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]) 

Si le preocupan las listas grandes, entonces reemplazaría zip por izip de itertools.

 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) 

Podría calcular la media utilizando una media móvil acumulativa para iterar solo una vez en las listas:

 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] 

Creo que lo que estás buscando es 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 

Ver también zip y sorted .

 >>> 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} 

Puede tener avg() return float(len(series)) si desea un promedio de punto flotante.