2009-04-06 15 views
8

Jaki jest najlepszy sposób zamiany listy/krotki w dyktando, gdzie klucze są odrębnymi wartościami listy, a wartości są częstościami tych odrębnych wartości?Najlepszy sposób na przekształcenie listy słów w dyktafon częstotliwości

Innymi słowy:

['a', 'b', 'b', 'a', 'b', 'c'] 
--> 
{'a': 2, 'b': 3, 'c': 1} 

(miałem coś jak wyżej tyle razy, czy jest coś w standardowej lib, który zrobi to za ciebie?)

EDIT:

Jacob Gabrielson wskazuje, jest something coming in the standard lib do 2,7/3,1 gałęzi

+0

Może zdefiniować, co masz na myśli przez najlepsze? Najbardziej wydajny? Mniejsza ilość kodu? Najłatwiejszy do zrozumienia? – Dana

Odpowiedz

14

rodzaju

from collections import defaultdict 
fq= defaultdict(int) 
for w in words: 
    fq[w] += 1 

To zwykle działa ładnie.

1

muszę podzielić się ciekawy ale niby śmieszne sposób z tym, że po prostu wymyślił:

>>> class myfreq(dict): 
...  def __init__(self, arr): 
...   for k in arr: 
...    self[k] = 1 
...  def __setitem__(self, k, v): 
...   dict.__setitem__(self, k, self.get(k, 0) + v) 
... 
>>> myfreq(['a', 'b', 'b', 'a', 'b', 'c']) 
{'a': 2, 'c': 1, 'b': 3} 
+0

(self.get (k) lub 0) można lepiej napisać jako self.get (k, 0) –

2

Jest to obrzydliwość, ale:

from itertools import groupby 
dict((k, len(list(xs))) for k, xs in groupby(sorted(items))) 

nie mogę wymyślcie powód, dla którego wybralibyśmy tę metodę w stosunku do S.Lott'a, ale jeśli ktoś chce to wskazać, równie dobrze mógłby to być ja. :)

+1

punktów za sprytność –

+0

Muszę powiedzieć, że właśnie to powiedziałem i przetestowałem pod kątem wydajności (liczę na liczenie zawiera dosłownie miliony obiektów) i uznał, że musi to być szybsze niż wielokrotne pobieranie/ustawianie map skrótu ... Ale jak się okazuje, zajmuje to 4 razy więcej czasu procesora w moich testach, kiedy musi posortować listę lub 2x kiedy lista jest już posortowana. Ciekawy. Jest to bardzo sprytne. – iAdjunct

+0

Jeśli korzystasz z milionów obiektów, lepiej zrezygnować z sortowania zewnętrznego (lub odładować sortowanie do silnika danych, z którego pochodzi dane wejście, jeśli to możliwe). Słowo "sort words.txt | Unikatowy kasztan w powłoce jest trudny do pobicia. –

22

uważam, że najłatwiej zrozumieć (podczas gdy może nie być najbardziej wydajne) sposób to zrobić:

{i:words.count(i) for i in set(words)} 
+2

+1: Muszę zdobyć trochę tego cukru syntaktycznego Pythona 3.0. –

+0

To jest całkiem gorące –

+0

Piękne Python! –

7

Tylko uwaga, że ​​wychodząc z Pythonem 2.7/3.1, funkcja ta będzie wbudowany w moduł collections, więcej informacji można znaleźć pod adresem this bug. Oto przykład z release notes:

>>> from collections import Counter 
>>> c=Counter() 
>>> for letter in 'here is a sample of english text': 
... c[letter] += 1 
... 
>>> c 
Counter({' ': 6, 'e': 5, 's': 3, 'a': 2, 'i': 2, 'h': 2, 
'l': 2, 't': 2, 'g': 1, 'f': 1, 'm': 1, 'o': 1, 'n': 1, 
'p': 1, 'r': 1, 'x': 1}) 
>>> c['e'] 
5 
>>> c['z'] 
0 
+2

wygląda jeszcze prostiej, wygląda na to, że możesz po prostu przekazać ciąg do konstruktora Counter i robi to za Ciebie. –

+2

Możesz po prostu zrobić 'Counter (word_list)'. –

1

postanowiłem iść dalej i przetestować wersje zasugerował, znalazłem collections.Counter jak sugeruje Jacob Gabrielson być najszybszy, a następnie wersji defaultdict przez Slott.

Oto moje kody: ze zbiorów importować defaultdict ze zbiorów importować Counter

import random 

# using default dict 
def counter_default_dict(list): 
    count=defaultdict(int) 
    for i in list: 
     count[i]+=1 
    return count 

# using normal dict 
def counter_dict(list): 
    count={} 
    for i in list: 
     count.update({i:count.get(i,0)+1}) 
    return count 

# using count and dict 
def counter_count(list): 
    count={i:list.count(i) for i in set(list)} 
    return count 

# using count and dict 
def counter_counter(list): 
    count = Counter(list) 
    return count 

list=sorted([random.randint(0,250) for i in range(300)]) 


if __name__=='__main__': 
    from timeit import timeit 
    print("collections.Defaultdict ",timeit("counter_default_dict(list)", setup="from __main__ import counter_default_dict,list", number=1000)) 
    print("Dict",timeit("counter_dict(list)",setup="from __main__ import counter_dict,list",number=1000)) 
    print("list.count ",timeit("counter_count(list)", setup="from __main__ import counter_count,list", number=1000)) 
    print("collections.Counter.count "timeit("counter_counter(list)", setup="from __main__ import counter_counter,list", number=1000)) 

i moich wyników:

collections.Defaultdict 
0.06787874956330614 
Dict 
0.15979115872995675 
list.count 
1.199258431219126 
collections.Counter.count 
0.025896202538920665 

daj mi znać, jak mogę poprawić analizę.

Powiązane problemy