2009-05-21 13 views
49

Jestem początkującym pytonem, więc może moje pytanie brzmi bardzo noob. Załóżmy, że mam listę słów, i chcę znaleźć liczbę razy, kiedy każde słowo pojawia się na tej liście. oczywistym sposobem na to jest:licznik częstotliwości przedmiotu w pytonie

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

Ale znajdę ten kod nie jest bardzo dobra, ponieważ w ten sposób program działa poprzez słowa listy dwa razy, raz do budowy zestawu, a drugi raz, licząc liczbę występów. Oczywiście, mógłbym napisać funkcję, aby uruchomić listę i zrobić liczenie, ale to nie byłoby tak pythonic. Czy istnieje bardziej wydajny i pytonowy sposób? (. Pętli listę zwiększając właściwego dict klucz)

+0

Nie dwa razy, wygląda na złożoność O (N * N). – Drakosha

+0

@ Drakosha: Zgadzam się, po prostu to widziałem. –

+1

Tak, złożoność to O (n^2), ale sama lista jest uruchamiana dwukrotnie. – Daniyar

Odpowiedz

89

defaultdict na ratunek!

from collections import defaultdict 

words = "apple banana apple strawberry banana lemon" 

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

To działa w O (n).

+7

+1, collections.defaultdict jest jednym z moich ulubionych kontenerów! –

+1

Powiedziałbym O (NlogN), jeśli kolekcja jest drzewem, lub O (N) w średniej, jeśli jest hash – Drakosha

+7

Dict jest hash. –

7

Jeśli nie chcesz używać standardowej metody słownika, można spróbować to:

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

To działa w czasie O (n log n) czas.

11

Standardowe podejście:

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

Czy istnieje różnica w złożoności? Czy groupby używa sortowania? Wydaje się, że potrzebujesz czasu O (nlogn)? – Daniyar

+0

Ups, wygląda na to, że Nick Presta poniżej wskazał, że podejście groupby wykorzystuje O (nlogn). – Daniyar

118

Jeśli używasz Pythona 2.7 +/3.1 +, istnieje Counter Class w module kolekcji, który jest specjalnie zaprojektowany, aby rozwiązać ten problem typ problemu:

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

Ponieważ zarówno 2.7, jak i 3.1 są nadal w fazie beta, Niby go używasz, więc pamiętaj, że standardowy sposób wykonywania tego rodzaju pracy wkrótce będzie dostępny.

+4

Wow! To jest sposób pytonowy. Dziękuję za udostępnienie tego. – Daniyar

+0

całkiem fajne! * Wraca do Pythona 2.5 :(* – Triptych

+0

Jest również w python 2.7. – nosklo

3

Bez 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

Wydaje się, że. Wolniejszy niż defaultdict w moich testach – nosklo

+0

Rozdzielanie przez spację jest zbędne.Należy również użyć metody dict.set_default zamiast try/except .. – Triptych

+2

To dużo wolniej, ponieważ używasz wyjątków. Wyjątki są bardzo kosztowne w prawie każdym języku Unikaj używania ich do gałęzi logicznych Spójrz na moje rozwiązanie prawie identyczną metodą, ale bez nas Wyjątki: 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 

myślę, że wyniki będą takie same, jak rozwiązania tryptyku, ale bez importowania kolekcji. Również trochę jak rozwiązanie Selinapa, ale bardziej czytelne imho. Prawie identyczne z rozwiązaniem Thomasa Weigela, ale bez użycia Wyjątków.

Może to być jednak wolniejsze niż użycie defaultdict() z biblioteki kolekcji. Ponieważ wartość jest pobierana, zwiększana, a następnie przypisywana ponownie. Zamiast tylko zwiększać. Jednak użycie + = może zrobić to samo wewnętrznie.

+0

Nice. Znalazłem to samo rozwiązanie tutaj: http://openbookproject.net/thinkcs/python/english3e/dictionaries.html#counting-letter. –

+0

Fajnie, czy powinienem poprosić o przypisanie? : p;) – hopla

0

Nie możesz po prostu użyć liczby?

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

Pytanie już używa "count", i prosi o lepsze alternatywy. – Daniyar

0

Odpowiedź poniżej trwa kilka dodatkowych cykli, ale to jest inna metoda

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

zdarzyło mi się pracować na jakimś Spark ćwiczenia, tutaj jest moje rozwiązanie.

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

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

** # wyjście powyżej **

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

Zastosowanie zmniejszenia() do konwersji listy do jednej dict.

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

powraca

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

Nadzieja to pomaga!