2013-08-20 4 views
7

Ich habe eine Liste von Werten. Ich wünsche für jede Klasse der Anzahl des Elements während einer Schleife zählen (dh 1,2,3,4,5)effiziente Möglichkeit, das Element in einem Wörterbuch in Python mit einer Schleife zu zählen

mylist = [1,1,1,1,1,1,2,3,2,2,2,2,3,3,4,5,5,5,5] 
mydict = dict() 
for index in mylist: 
    mydict[index] = +1 
mydict 
Out[344]: {1: 1, 2: 1, 3: 1, 4: 1, 5: 1} 

Ich möchte dieses Ergebnis

Out[344]: {1: 6, 2: 5, 3: 3, 4: 1, 5: 4} 
+5

'collections.Counter', in Ihrem Code benötigen Sie:' mydict [index] + = 1' –

+0

Könnte ich bitte ein Beispiel fragen? danke im voraus –

+0

'sammlungen.Zähler (meine liste)' und du bist fertig. (Nun, abgesehen von dem Importieren von 'Sammlungen', und Sie müssen immer noch tun, was auch immer Sie mit den Zählungen tun würden, aber' Sammlungen.Zähler (Meine Liste) 'ist die gesamte" Dinge zählen "-Phase.) – user2357112

Antwort

13

Für Ihre kleineren Beispiel mit einer begrenzten Vielfalt von Elementen, können Sie einen Satz verwenden können und ein dict Verständnis:

>>> mylist = [1,1,1,1,1,1,2,3,2,2,2,2,3,3,4,5,5,5,5] 
>>> {k:mylist.count(k) for k in set(mylist)} 
{1: 6, 2: 5, 3: 3, 4: 1, 5: 4} 

zu brechen es down, set(mylist) unifiziert die Liste und macht es kompakter:

>>> set(mylist) 
set([1, 2, 3, 4, 5]) 

Dann schreitet das Wörterbuchverständnis durch die eindeutigen Werte und setzt die Zählung aus der Liste.

Dies ist auch deutlich schneller als Zähler verwendet und schneller als setdefault mit:

from __future__ import print_function 
from collections import Counter 
from collections import defaultdict 
import random 

mylist=[1,1,1,1,1,1,2,3,2,2,2,2,3,3,4,5,5,5,5]*10 

def s1(mylist): 
    return {k:mylist.count(k) for k in set(mylist)} 

def s2(mlist): 
    return Counter(mylist) 

def s3(mylist): 
    mydict=dict() 
    for index in mylist: 
     mydict[index] = mydict.setdefault(index, 0) + 1 
    return mydict 

def s4(mylist): 
    mydict={}.fromkeys(mylist,0) 
    for k in mydict: 
     mydict[k]=mylist.count(k)  
    return mydict  

def s5(mylist): 
    mydict={} 
    for k in mylist: 
     mydict[k]=mydict.get(k,0)+1 
    return mydict  

def s6(mylist): 
    mydict=defaultdict(int) 
    for i in mylist: 
     mydict[i] += 1 
    return mydict  

def s7(mylist): 
    mydict={}.fromkeys(mylist,0) 
    for e in mylist: 
     mydict[e]+=1  
    return mydict  

if __name__ == '__main__': 
    import timeit 
    n=1000000 
    print(timeit.timeit("s1(mylist)", setup="from __main__ import s1, mylist",number=n)) 
    print(timeit.timeit("s2(mylist)", setup="from __main__ import s2, mylist, Counter",number=n)) 
    print(timeit.timeit("s3(mylist)", setup="from __main__ import s3, mylist",number=n)) 
    print(timeit.timeit("s4(mylist)", setup="from __main__ import s4, mylist",number=n)) 
    print(timeit.timeit("s5(mylist)", setup="from __main__ import s5, mylist",number=n)) 
    print(timeit.timeit("s6(mylist)", setup="from __main__ import s6, mylist, defaultdict",number=n)) 
    print(timeit.timeit("s7(mylist)", setup="from __main__ import s7, mylist",number=n)) 

Auf meinem Rechner, die Drucke (Python 3):

18.123854104997008   # set and dict comprehension 
78.54796334600542   # Counter 
33.98185228800867   # setdefault 
19.0563529439969   # fromkeys/count 
34.54294775899325   # dict.get 
21.134678319009254   # defaultdict 
22.760544238000875   # fromkeys/loop 

Für größere Listen, wie 10 Millionen Integer, mit mehr verschiedenen Elementen (1.500 zufällige Ints), verwenden defaultdict oder fromkeys in einer Schleife:

from __future__ import print_function 
from collections import Counter 
from collections import defaultdict 
import random 

mylist = [random.randint(0,1500) for _ in range(10000000)] 

def s1(mylist): 
    return {k:mylist.count(k) for k in set(mylist)} 

def s2(mlist): 
    return Counter(mylist) 

def s3(mylist): 
    mydict=dict() 
    for index in mylist: 
     mydict[index] = mydict.setdefault(index, 0) + 1 
    return mydict 

def s4(mylist): 
    mydict={}.fromkeys(mylist,0) 
    for k in mydict: 
     mydict[k]=mylist.count(k)  
    return mydict  

def s5(mylist): 
    mydict={} 
    for k in mylist: 
     mydict[k]=mydict.get(k,0)+1 
    return mydict  

def s6(mylist): 
    mydict=defaultdict(int) 
    for i in mylist: 
     mydict[i] += 1 
    return mydict  

def s7(mylist): 
    mydict={}.fromkeys(mylist,0) 
    for e in mylist: 
     mydict[e]+=1  
    return mydict  

if __name__ == '__main__': 
    import timeit 
    n=1 
    print(timeit.timeit("s1(mylist)", setup="from __main__ import s1, mylist",number=n)) 
    print(timeit.timeit("s2(mylist)", setup="from __main__ import s2, mylist, Counter",number=n)) 
    print(timeit.timeit("s3(mylist)", setup="from __main__ import s3, mylist",number=n)) 
    print(timeit.timeit("s4(mylist)", setup="from __main__ import s4, mylist",number=n)) 
    print(timeit.timeit("s5(mylist)", setup="from __main__ import s5, mylist",number=n)) 
    print(timeit.timeit("s6(mylist)", setup="from __main__ import s6, mylist, defaultdict",number=n)) 
    print(timeit.timeit("s7(mylist)", setup="from __main__ import s7, mylist",number=n)) 

Drucke:

2825.2697427899984    # set and dict comprehension 
42.607481333994656    # Counter 
22.77713537499949    # setdefault 
2853.11187016801    # fromkeys/count 
23.241977066005347    # dict.get 
15.023175164998975    # defaultdict 
18.28165417900891    # fromkeys/loop 

Sie können sehen, dass Lösungen, die auf count mit einer moderaten Anzahl von Malen durch die große Liste Relais werden im Vergleich zu anderen Lösungen schlecht/katastrophal leiden.

6

erhalten Versuchen collections.Counter:

>>> from collections import Counter 
    >>> Counter([1,1,1,1,1,1,2,3,2,2,2,2,3,3,4,5,5,5,5]) 
    Counter({1: 6, 2: 5, 5: 4, 3: 3, 4: 1}) 

In Ihrem Code können Sie im Grunde ersetzen mydict mit einem Counter und schreiben

mydict[index] += 1 

statt

mydict[index] = +1 
+0

Danke, aber es tut mir leid, weil ich einen Weg innerhalb der Schleife finden muss. Die Liste war ein Beispiel, weil ich 32 GB Daten in einer Schleife ausführen muss/ –

+3

Wenn Sie einen Iterator über Ihre 32 GB Elemente haben, funktioniert 'collections.Counter' genauso wie mit einer Liste. – user2357112

3

Code zu beheben:

mydict[index] = +1 

sollte sein:

mydict[index] = mydict.setdefault(index, 0) + 1 
+0

Danke. mit deinem Beispiel habe ich {1: 7, 2: 6, 3: 4, 4: 2, 5: 5} bekommen. Der beste Weg ist mydict [index] = mydict.get (index, 0) + 1 –

+1

@Gianni Oh, ich habe gerade korrigiert, ich bin neuer Python Lerner, also habe ich eine einfache Antwort gepostet. –

+2

Ich würde sagen, der beste Weg ist ein Counter selbst, aufgrund der Einfachheit, aber dieser Weg funktioniert. – rlms

1

Ihr Code für jede Taste 1 als Wert zuweist. Ersetzen mydict[index] = +1 mit mylist.count(index)

Dies sollte funktionieren:

mylist = [1,1,1,1,1,1,2,3,2,2,2,2,3,3,4,5,5,5,5] 
mydict = dict() 
for index in mylist: 
    mydict[index] = mylist.count(index) 
mydict 
4

Eine Variante des setdefault Ansatzes ist die collections.defaultdict. Das ist ein bisschen schneller.

def foo(mylist): 
    d=defaultdict(int) 
    for i in mylist: 
     d[i] += 1 
    return d 

itertools.groupBy bietet eine weitere Option. Es ist Geschwindigkeit ist etwa die gleiche wie Counter (zumindest auf 2,7)

{x[0]:len(list(x[1])) for x in itertools.groupby(sorted(mylist))} 

jedoch Zeittests auf dieser kleine Testliste möglicherweise nicht das gleiche sein, wenn das 32 GB Daten zu tun, dass die OP in einem Kommentar erwähnt.


Ich lief Fall mehrere dieser Optionen in der Wortanzahl in python top N word count, why multiprocess slower then single process

Dort wird der OP verwendet Zähler, und versuchte, die Dinge durch die Verwendung Multiprozessing zu beschleunigen. Mit einer 1.2Mb Textdatei war der Zähler mit defaultdict schnell, dauert 0,2 Sekunden. Das Sortieren der Ausgabe, um die oberen 40 Wörter zu erhalten, dauerte so lange wie das Zählen selbst.

Counter war etwas langsamer auf 3.2, und viel langsamer auf 2.7. Das liegt daran, 3.2 eine kompilierte Version (.so Datei).

Aber der Zähler mit mylist.count Boden bis zum Stillstand bei der Verarbeitung einer großen Liste; fast 200 Sekunden Es muss diese große Liste mehrmals durchsuchen, einmal, um Schlüssel zu sammeln, und dann einmal für jeden Schlüssel, wenn es zählt.