2009-05-21 16 views
49

Soy un principiante de python, así que tal vez mi pregunta es muy novato. Supongamos que tengo una lista de palabras, y quiero encontrar el número de veces que aparece cada palabra en esa lista. manera obvia de hacerlo es:recuento de frecuencia de elemento en python

words = "apple banana apple strawberry banana lemon" 
uniques = set(words.split()) 
freqs = [(item, words.split.count(item)) for item in uniques] 
print(freqs) 

Pero este código no parece muy buena, ya que este programa forma corre a través de palabras lista dos veces, una para construir el conjunto, y la segunda vez contar el número de apariciones. Por supuesto, podría escribir una función para ejecutar la lista y hacer el recuento, pero eso no sería tan pitónico. Entonces, ¿hay una manera más eficiente y pitónica? (. Bucle a través de la lista de incrementar el dict adecuada llave)

+0

No dos veces, parece que O (N * N) complejidad – Drakosha

+0

@Drakosha: De acuerdo, acabo de ver esto también. –

+1

Sí, la complejidad es O (n^2), pero la lista en sí misma se ejecuta dos veces. – Daniyar

Respuesta

89

defaultdict al rescate!

from collections import defaultdict 

words = "apple banana apple strawberry banana lemon" 

d = defaultdict(int) 
for word in words.split(): 
    d[word] += 1 

Esto se ejecuta en O (n).

+7

+1, collections.defaultdict es uno de mis contenedores favoritos! –

+1

Diría que O (NlogN) si la colección es un árbol, o O (N) en promedio si es un hash – Drakosha

+7

dict es un hash. –

7

Si no desea utilizar el método estándar de diccionario, puede intentar esto:

>>> from itertools import groupby 
>>> myList = words.split() # ['apple', 'banana', 'apple', 'strawberry', 'banana', 'lemon'] 
>>> [(k, len(list(g))) for k, g in groupby(sorted(myList))] 
[('apple', 2), ('banana', 2), ('lemon', 1), ('strawberry', 1)] 

Se ejecuta en O (n log n) hora.

11

enfoque estándar:

from collections import defaultdict 

words = "apple banana apple strawberry banana lemon" 
words = words.split() 
result = collections.defaultdict(int) 
for word in words: 
    result[word] += 1 

print result 

GroupBy oneliner:

from itertools import groupby 

words = "apple banana apple strawberry banana lemon" 
words = words.split() 

result = dict((key, len(list(group))) for key, group in groupby(sorted(words))) 
print result 
+0

¿Hay alguna diferencia en complejidad? ¿Groupby usa la clasificación? Entonces parece necesitar el tiempo O (nlogn)? – Daniyar

+0

Vaya, parece que Nick Presta a continuación ha señalado que el enfoque groupby usa O (nlogn). – Daniyar

118

Si está utilizando Python 2.7 +/3.1 +, hay una Counter Class en el módulo de colecciones que está construido para resolver este tipo de problema:

>>> from collections import Counter 
>>> words = "apple banana apple strawberry banana lemon" 
>>> freqs = Counter(words.split()) 
>>> print(freqs) 
Counter({'apple': 2, 'banana': 2, 'strawberry': 1, 'lemon': 1}) 
>>> 

Dado que tanto el 2.7 como el 3.1 siguen en beta, es usted Es muy probable que lo esté usando, así que tenga en cuenta que una forma estándar de hacer este tipo de trabajo pronto estará disponible.

+4

¡Guau! Esta es la manera pitónica. Gracias por compartir esto. – Daniyar

+0

¡bastante guay! * Vuelve a Python 2.5 :(* – Triptych

+0

También está en Python 2.7. – nosklo

3

Sin defaultdict:

words = "apple banana apple strawberry banana lemon" 
my_count = {} 
for word in words.split(): 
    try: my_count[word] += 1 
    except KeyError: my_count[word] = 1 
+0

Parece más lento que el default en mis pruebas – nosklo

+0

dividir por un espacio es redundante. Además, debe usar el método dict.set_default en lugar de try/except. – Triptych

+2

Es mucho más lento porque está utilizando Excepciones. Las excepciones son muy costosas en casi cualquier idioma Evite usarlos para las ramas lógicas. Mire mi solución por un método casi idéntico, pero sin nosotros Excepciones: http://stackoverflow.com/questions/893417/item-frequency-count-in-python/983434#983434 – hopla

7
freqs = {} 
for word in words: 
    freqs[word] = freqs.get(word, 0) + 1 # fetch and increment OR initialize 

Creo que esto da a los mismos que la solución de tríptico, pero sin importar colecciones. También es un poco como la solución de Selinap, pero es más fácil de leer. Casi idéntica a la solución de Thomas Weigel, pero sin usar Excepciones.

Sin embargo, esto podría ser más lento que usar defaultdict() desde la biblioteca de colecciones. Dado que el valor se obtiene, se incrementa y luego se asigna de nuevo. En lugar de simplemente incrementado. Sin embargo, usar + = podría hacer lo mismo internamente.

+0

Nice. Encontré esta misma solución aquí: http://openbookproject.net/thinkcs/python/english3e/dictionaries.html#counting-letters. –

+0

Cool, ¿debería pedir una atribución? : p;) – hopla

0

¿No puedes simplemente usar la cuenta?

words = 'the quick brown fox jumps over the lazy gray dog' 
words.count('z') 
#output: 1 
+1

La pregunta ya usa "conteo" y pregunta por mejores alternativas. – Daniyar

0

La respuesta a continuación tiene algunos ciclos extra, pero es otro método

def func(tup): 
    return tup[-1] 


def print_words(filename): 
    f = open("small.txt",'r') 
    whole_content = (f.read()).lower() 
    print whole_content 
    list_content = whole_content.split() 
    dict = {} 
    for one_word in list_content: 
     dict[one_word] = 0 
    for one_word in list_content: 
     dict[one_word] += 1 
    print dict.items() 
    print sorted(dict.items(),key=func) 
0

Me pasó a trabajar en algo de ejercicio Spark, aquí está mi solución.

tokens = ['quick', 'brown', 'fox', 'jumps', 'lazy', 'dog'] 

print {n: float(tokens.count(n))/float(len(tokens)) for n in tokens} 

** # salida del anterior **

{'brown': 0.16666666666666666, 'lazy': 0.16666666666666666, 'jumps': 0.16666666666666666, 'fox': 0.16666666666666666, 'dog': 0.16666666666666666, 'quick': 0.16666666666666666} 
0

Uso reducir() para convertir la lista a un solo dict.

words = "apple banana apple strawberry banana lemon" 
reduce(lambda d, c: d.update([(c, d.get(c,0)+1)]) or d, words.split(), {}) 

vuelve

{'strawberry': 1, 'lemon': 1, 'apple': 2, 'banana': 2} 
0
words = "apple banana apple strawberry banana lemon" 
w=words.split() 
e=list(set(w))  
for i in e: 
    print(w.count(i)) #Prints frequency of every word in the list 

Espero que esto ayude!

Cuestiones relacionadas