2009-05-21 19 views
49

Sono un novizio pitone, quindi forse la mia domanda è molto noob. Supponiamo che io abbia una lista di parole e voglio trovare il numero di volte in cui ogni parola appare in quella lista. modo ovvio per farlo è:conteggio delle frequenze degli oggetti in pitone

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

Ma ho trovato questo codice non è molto buono, perché questo programma così funziona attraverso parole elenco due volte, una volta per costruire il set, e la seconda volta contare il numero di presenze. Ovviamente, potrei scrivere una funzione per scorrere l'elenco e fare il conteggio, ma non sarebbe così pignolo. Quindi, c'è un modo più efficiente e pietoso? (. Scorrendo la lista incrementare il corretto dict chiave)

+0

Non due volte, sembra complessità O (N * N) – Drakosha

+0

@Drakosha: D'accordo, ho visto anche questo. –

+1

Sì, la complessità è O (n^2), ma l'elenco stesso viene eseguito due volte. – Daniyar

risposta

89

defaultdict per il salvataggio!

from collections import defaultdict 

words = "apple banana apple strawberry banana lemon" 

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

Viene eseguito in O (n).

+7

+1, collections.defaultdict è uno dei miei contenitori preferiti! –

+1

Direi O (NlogN) se la raccolta è un albero o O (N) in media se si tratta di un hash – Drakosha

+7

dict è un hash. –

7

Se non si desidera utilizzare il metodo di dizionario standard, si può provare questo:

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

Viene eseguito in O (n log n) tempo.

11

approccio standard:

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

C'è una differenza di complessità? Groupby usa l'ordinamento? Allora sembra che abbia bisogno del tempo di O (nlogn)? – Daniyar

+0

Oops, sembra che Nick Presta di seguito abbia sottolineato che l'approccio groupby utilizza O (nlogn). – Daniyar

118

Se si utilizza python 2.7 +/3.1 +, c'è un Counter Class nel modulo di collezioni che è appositamente costruito per risolvere questo tipo di 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}) 
>>> 

Dal momento che entrambi i 2.7 e 3.1 sono ancora in beta, sei tu nlikely lo stai usando, quindi tieni a mente che un modo standard per fare questo tipo di lavoro sarà presto disponibile.

+4

Wow! Questo è il modo pititico. Grazie per aver condiviso questo. – Daniyar

+0

davvero fantastico! * Torna a Python 2.5 :(* – Triptych

+0

È anche in Python 2.7 – nosklo

3

Senza 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

Sembra più lento di defaultdict nei miei test – nosklo

+0

la divisione da uno spazio è ridondante.Inoltre, dovresti usare il metodo dict.set_default invece di try/except. – Triptych

+2

È molto più lento perché stai usando Eccezioni.Le eccezioni sono molto costose in quasi tutte le lingue Evita di usarli per i rami logici Guarda la mia soluzione per un metodo quasi identico, ma senza di noi Eccezioni: 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 

Credo che questo si traduce per la stessa soluzione del Trittico, ma senza importare collezioni. Anche un po 'come la soluzione di Selinap, ma imho più leggibile. Quasi identico alla soluzione di Thomas Weigel, ma senza usare Eccezioni.

Questo potrebbe essere più lento rispetto all'uso di defaultdict() dalla libreria delle collezioni. Poiché il valore viene recuperato, incrementato e quindi nuovamente assegnato. Invece di appena incrementato. Tuttavia usare + = potrebbe fare lo stesso internamente.

+0

Nizza. Ho trovato questa stessa soluzione qui: http://openbookproject.net/thinkcs/python/english3e/dictionaries.html#counting-letters. –

+0

Cool, dovrei chiedere l'attribuzione? : p;) – hopla

0

Non puoi usare il conteggio?

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

La domanda usa già "conta" e chiede alternative migliori. – Daniyar

0

La risposta di seguito prende alcuni cicli in più, ma è un altro metodo

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

mi è capitato di lavorare su qualche esercizio Spark, ecco la mia soluzione.

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

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

** # uscita di quanto sopra **

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

Usa a ridurre() per convertire l'elenco per un singolo dict.

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

rendimenti

{'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 

Spero che questo aiuti!

Problemi correlati