Encontrar frecuencias de elementos de pares en una lista de pares

Digamos que tengo una larga lista de este tipo:

text = [ ['a', 'b'], ['a', 'd'], ['w', 'a'], ['a', 'b'], ... ] 

Dados los primeros elementos, quiero construir un diccionario que muestre un recuento de los segundos elementos. Por ejemplo, en el ejemplo particular anterior, me gustaría tener algo como esto:

 {'a': {'b':2, 'd':1}, 'w': {'a':1} } 

Así es como intenté resolverlo sin éxito. Construí una lista de primeros elementos únicos. Llamémoslo words y luego:

 dic = {} for word in words: inner_dic = {} for pair in text: if pair[0] == word: num = text.count(pair) inner_dic[pair[1]] = num dic[pair[0]] = inner_dic 

Obtengo un resultado obviamente erróneo. Un problema con el código es que sobre-cuenta pares. No estoy seguro de cómo resolver esto.

Deberías hacer esto en su lugar:

 for word in words: inner_dic = {} for pair in text: if pair[0] == word: num = text.count(pair) inner_dic[pair[1]] = num dic[word] = inner_dic 

es decir, deberías hacer dic[word] lugar de dic[pair[0]] , que asignará la inner_dic al primer elemento del último pair marcado, incluso si pair[0] no es word .

El módulo de colecciones hace un trabajo corto de tareas como esta.

Use un contador para la parte de conteo (es un tipo de diccionario que devuelve 0 para los valores faltantes, lo que facilita el uso de +=1 para los conteos en aumento). Use defaultdict para el dictador externo (puede hacer automáticamente un nuevo contador para cada prefijo “primero”):

 >>> from collections import defaultdict, Counter >>> d = defaultdict(Counter) >>> text = [ ['a', 'b'], ['a', 'd'], ['w', 'a'], ['a', 'b']] >>> for first, second in text: d[first][second] += 1 

Aquí está el equivalente usando diccionarios regulares:

 text = [ ['a', 'b'], ['a', 'd'], ['w', 'a'], ['a', 'b']] d = {} for first, second in text: if first not in d: d[first] = {} inner_dict = d[first] if second not in inner_dict: inner_dict[second] = 0 inner_dict[second] += 1 

El camino corto o el largo funcionarán perfectamente con el módulo json (tanto Counter como defaultdict son tipos de dictados que pueden codificarse con JSON).

Espero que esto ayude. Buena suerte con tu análisis de texto 🙂

Puede usar un código predeterminado combinado con un dictado de contador :

 from collections import Counter, defaultdict d = defaultdict(Counter) text = [ ['a', 'b'], ['a', 'd'], ['w', 'a'], ['a', 'b'] ] for k, v in text: d[k][v] += 1 # for single value # d[k].update(v) for multiple values ie list of words from pprint import pprint as pp pp(d) {'a': Counter({'b': 2, 'd': 1}), 'w': Counter({'a': 1})} 

El código predeterminado creará una nueva combinación clave / valor donde el valor es un dictado de contador. Si la clave no existe, si existe la clave, solo actualizaremos el valor utilizando Counter.update que, a diferencia de dict.update, incrementará el valor y no se sobrescribirá.

utilizando un dict normal sin importaciones, podemos usar dict.setdefault que creará un nuevo dict como valor para cada clave k y establecerá un valor predeterminado de 0 para cada subclave v :

 d = {} text = [ ['a', 'b'], ['a', 'd'], ['w', 'a'], ['a', 'b'] ] for k, v in text: d.setdefault(k, {}).setdefault(v,0) d[k][v] += 1 pp(d) {'a': {'b': 2, 'd': 1}, 'w': {'a': 1}} 

Aquí hay una forma de usar el método .setdefault :

 text = [ ['a', 'b'], ['a', 'd'], ['w', 'a'], ['a', 'b'] ] result={} for x, y in text: result.setdefault(x, {}).setdefault(y,0) result[x][y]+=1 >>> result {'a': {'b': 2, 'd': 1}, 'w': {'a': 1}} 

No se requiere una biblioteca externa.

 text = [ ['a', 'b'], ['a', 'd'], ['w', 'a'], ['a', 'b']] d = {} for i in text: if d.get(i[0]): if d[i[0]].get(i[1]): d[i[0]][i[1]] +=1 else: d[i[0]][i[1]] = 1 else: d[i[0]] = {i[1] : 1} print d >>>{'a': {'b': 2, 'd': 1}, 'w': {'a': 1}}