Come contare la frequenza degli elementi in un elenco non ordinato?


237

Devo trovare la frequenza degli elementi in un elenco non ordinato

a = [1,1,1,1,2,2,2,2,3,3,4,5,5]

output->

b = [4,4,2,1,2]

Inoltre voglio rimuovere i duplicati da a

a = [1,2,3,4,5]

Sono sempre ordinati come in questo esempio?
Farinha,

@Peter. Sì, hai ordinato l'elenco ai fini della pubblicazione. L'elenco sarà sempre ordinato?
S. Lott

2
No, l'elenco non verrà ordinato sempre. Questo non è un compito.
Bruce,

Sto cercando di tracciare il grafico della distribuzione dei gradi di una rete.
Bruce,

5
@Peter: aggiorna la tua domanda con le informazioni utili. Non aggiungere commenti alla tua domanda: sei il proprietario della domanda, puoi correggerla per renderla completa e chiara.
S. Lott

Risposte:


147

Nota: è necessario ordinare l'elenco prima dell'uso groupby.

È possibile utilizzare groupbydal itertoolspacchetto se l'elenco è un elenco ordinato.

a = [1,1,1,1,2,2,2,2,3,3,4,5,5]
from itertools import groupby
[len(list(group)) for key, group in groupby(a)]

Produzione:

[4, 4, 2, 1, 2]

bello, usando groupby. Mi chiedo per la sua efficienza contro l'approccio dict, però
Eli Bendersky il

32
Il groupby python crea nuovi gruppi quando cambia il valore che vede. In questo caso 1,1,1,2,1,1,1] restituirebbe [3,1,3]. Se ti aspettavi [6,1], assicurati di ordinare i dati prima di utilizzare groupby.
Evan,

4
@CristianCiupitu: sum(1 for _ in group).
Martijn Pieters

6
Questa non è una soluzione. L'output non dice cosa è stato contato.
buhtz,

8
[(key, len(list(group))) for key, group in groupby(a)]o {key: len(list(group)) for key, group in groupby(a)}@buhtz
Eric Pauley il

532

In Python 2.7 (o più recente), puoi usare collections.Counter:

import collections
a = [1,1,1,1,2,2,2,2,3,3,4,5,5]
counter=collections.Counter(a)
print(counter)
# Counter({1: 4, 2: 4, 3: 2, 5: 2, 4: 1})
print(counter.values())
# [4, 4, 2, 1, 2]
print(counter.keys())
# [1, 2, 3, 4, 5]
print(counter.most_common(3))
# [(1, 4), (2, 4), (3, 2)]

Se stai usando Python 2.6 o precedente, puoi scaricarlo qui .


1
@unutbu: cosa succede se ho tre elenchi, a, b, c per i quali aeb rimangono gli stessi, ma c cambia? Come contare il valore di c per cui a e c sono uguali?
ThePredator,

@Srivatsan: non capisco la situazione. Si prega di inviare una nuova domanda in cui è possibile elaborare.
unutbu,

1
C'è un modo per estrarre il dizionario {1: 4, 2: 4, 3: 2, 5: 2, 4: 1} dall'oggetto contatore?
Pavan,

7
@Pavan: collections.Counterè una sottoclasse di dict. Puoi usarlo come faresti con un normale dict. Se vuoi davvero un dict, tuttavia, puoi convertirlo in un dict usando dict(counter).
unutbu,

1
Funziona anche in 3.6, quindi supponiamo qualcosa di più grande di 2.7
kpierce8

108

Python 2.7+ introduce la comprensione del dizionario. La creazione del dizionario dall'elenco ti consentirà di contare e di eliminare i duplicati.

>>> a = [1,1,1,1,2,2,2,2,3,3,4,5,5]
>>> d = {x:a.count(x) for x in a}
>>> d
{1: 4, 2: 4, 3: 2, 4: 1, 5: 2}
>>> a, b = d.keys(), d.values()
>>> a
[1, 2, 3, 4, 5]
>>> b
[4, 4, 2, 1, 2]

Funziona davvero bene con elenchi di stringhe anziché numeri interi come la domanda originale posta.
Glen Selle,

15
È più veloce usando un set:{x:a.count(x) for x in set(a)}
stenci,

45
Questo è estremamente inefficiente . a.count()fa una traversata completa per ogni elemento in a, rendendo questo un approccio quadradico O (N ^ 2). collections.Counter()è molto più efficiente perché conta nel tempo lineare (O (N)). In numeri, ciò significa che questo approccio eseguirà 1 milione di passaggi per un elenco di lunghezza 1000, anziché solo 1000 passaggi con Counter(), 10 ^ 12 passaggi in cui sono necessari solo 10 ^ 6 da Counter per un milione di elementi in un elenco, ecc.
Martijn Pieters

3
@stenci: certo, ma l'orrore di usare a.count()completamente nani l'efficienza di aver usato un set lì.
Martijn Pieters

2
@MartijnPieters un motivo in più per usarlo meno volte :)
stenci

48

Per contare il numero di presenze:

from collections import defaultdict

appearances = defaultdict(int)

for curr in a:
    appearances[curr] += 1

Per rimuovere i duplicati:

a = set(a) 

1
+1 per collections.defaultdict. Inoltre, in Python 3.x, cerca le raccolte. È lo stesso di collections.defaultdict (int).
hughdbrown,

2
@hughdbrown, in realtà Counterpuò usare più tipi numerici incluso floato Decimal, non solo int.
Cristian Ciupitu,

28

In Python 2.7+, puoi usare le collezioni. Contatore per contare gli oggetti

>>> a = [1,1,1,1,2,2,2,2,3,3,4,5,5]
>>>
>>> from collections import Counter
>>> c=Counter(a)
>>>
>>> c.values()
[4, 4, 2, 1, 2]
>>>
>>> c.keys()
[1, 2, 3, 4, 5]

1
Il contatore è molto più lento del dict predefinito e il dict predefinito è molto più lento dell'uso manuale di un dict.
Jonathan Ray,

@JonathanRay, non più, stackoverflow.com/a/27802189/1382487 .
wsaleem,

25

Il conteggio della frequenza degli elementi viene probabilmente eseguito meglio con un dizionario:

b = {}
for item in a:
    b[item] = b.get(item, 0) + 1

Per rimuovere i duplicati, utilizzare un set:

a = list(set(a))

3
@phkahler: Il mio sarebbe solo un pochino meglio di così. Non vale la pena pubblicare una risposta separata quando questa può essere migliorata con una piccola modifica. Il punto di SO è quello di ottenere le migliori risposte. Potrei semplicemente modificarlo, ma preferisco consentire all'autore originale di apportare i propri miglioramenti.
S.Lott

1
@ S.Lott Il codice è molto più pulito senza dover importare defaultdict.
bstrauch24,

Perché non preinitialize B: b = {k:0 for k in a}?
DylanYoung,

20

Ecco un'altra alternativa succinta itertools.groupbyche funziona anche con input non ordinati:

from itertools import groupby

items = [5, 1, 1, 2, 2, 1, 1, 2, 2, 3, 4, 3, 5]

results = {value: len(list(freq)) for value, freq in groupby(sorted(items))}

risultati

{1: 4, 2: 4, 3: 2, 4: 1, 5: 2}

16

Puoi farlo:

import numpy as np
a = [1,1,1,1,2,2,2,2,3,3,4,5,5]
np.unique(a, return_counts=True)

Produzione:

(array([1, 2, 3, 4, 5]), array([4, 4, 2, 1, 2], dtype=int64))

Il primo array è valori e il secondo array è il numero di elementi con questi valori.

Quindi, se vuoi ottenere solo un array con i numeri, dovresti usare questo:

np.unique(a, return_counts=True)[1]

8
from collections import Counter
a=["E","D","C","G","B","A","B","F","D","D","C","A","G","A","C","B","F","C","B"]

counter=Counter(a)

kk=[list(counter.keys()),list(counter.values())]

pd.DataFrame(np.array(kk).T, columns=['Letter','Count'])

Sebbene questo frammento di codice possa essere la soluzione, includere una spiegazione aiuta davvero a migliorare la qualità del tuo post. Ricorda che stai rispondendo alla domanda per i lettori in futuro, e quelle persone potrebbero non conoscere i motivi del tuo suggerimento sul codice
Rahul Gupta,

Sì, lo farà Rahul Gupta
Anirban Lahiri il

7
seta = set(a)
b = [a.count(el) for el in seta]
a = list(seta) #Only if you really want it.

4
l'utilizzo di liste countè ridicolmente costoso e non richiesto in questo scenario.
Idan K,

@IdanK perché contare è costoso?
Kritika Rajain,

@KritikaRajain Per ogni elemento univoco nell'elenco, si scorre ripetutamente l'intero elenco per generare un conteggio (quadratico nel numero di elementi univoci nell'elenco). Al contrario, è possibile scorrere una volta l'elenco e contare il numero di ciascun elemento univoco (lineare nella dimensione dell'elenco). Se l'elenco contiene solo un elemento univoco, il risultato sarà lo stesso. Inoltre, questo approccio richiede un set intermedio aggiuntivo.
DylanYoung,


4

Per la tua prima domanda, ripeti l'elenco e usa un dizionario per tenere traccia di un'esistenza di elementi.

Per la tua seconda domanda, usa semplicemente l'operatore set.


4
Puoi per favore approfondire la prima risposta
Bruce,

3

Questa risposta è più esplicita

a = [1,1,1,1,2,2,2,2,3,3,3,4,4]

d = {}
for item in a:
    if item in d:
        d[item] = d.get(item)+1
    else:
        d[item] = 1

for k,v in d.items():
    print(str(k)+':'+str(v))

# output
#1:4
#2:4
#3:3
#4:2

#remove dups
d = set(a)
print(d)
#{1, 2, 3, 4}

3
def frequencyDistribution(data):
    return {i: data.count(i) for i in data}   

print frequencyDistribution([1,2,3,4])

...

 {1: 1, 2: 1, 3: 1, 4: 1}   # originalNumber: count

3

Sono piuttosto in ritardo, ma funzionerà anche e aiuterà gli altri:

a = [1,1,1,1,2,2,2,2,3,3,4,5,5]
freq_list = []
a_l = list(set(a))

for x in a_l:
    freq_list.append(a.count(x))


print 'Freq',freq_list
print 'number',a_l

produrrà questo ..

Freq  [4, 4, 2, 1, 2]
number[1, 2, 3, 4, 5]

2
a = [1,1,1,1,2,2,2,2,3,3,4,5,5]

# 1. Get counts and store in another list
output = []
for i in set(a):
    output.append(a.count(i))
print(output)

# 2. Remove duplicates using set constructor
a = list(set(a))
print(a)
  1. La raccolta di insiemi non consente duplicati, passando un elenco al costruttore set () si otterrà un iterabile di oggetti totalmente unici. La funzione count () restituisce un conteggio intero quando viene passato un oggetto che si trova in un elenco. Con ciò vengono conteggiati gli oggetti univoci e ogni valore di conteggio viene archiviato aggiungendo un output di elenco vuoto
  2. Il costruttore list () viene utilizzato per convertire il set (a) in elenco e riferito dalla stessa variabile a

Produzione

D:\MLrec\venv\Scripts\python.exe D:/MLrec/listgroup.py
[4, 4, 2, 1, 2]
[1, 2, 3, 4, 5]

2

Soluzione semplice usando un dizionario.

def frequency(l):
     d = {}
     for i in l:
        if i in d.keys():
           d[i] += 1
        else:
           d[i] = 1

     for k, v in d.iteritems():
        if v ==max (d.values()):
           return k,d.keys()

print(frequency([10,10,10,10,20,20,20,20,40,40,50,50,30]))

max(d.values())non cambierà nell'ultimo loop. Non calcolarlo nel ciclo, calcolarlo prima del ciclo.
DylanYoung,

1
#!usr/bin/python
def frq(words):
    freq = {}
    for w in words:
            if w in freq:
                    freq[w] = freq.get(w)+1
            else:
                    freq[w] =1
    return freq

fp = open("poem","r")
list = fp.read()
fp.close()
input = list.split()
print input
d = frq(input)
print "frequency of input\n: "
print d
fp1 = open("output.txt","w+")
for k,v in d.items():
fp1.write(str(k)+':'+str(v)+"\n")
fp1.close()

1
num=[3,2,3,5,5,3,7,6,4,6,7,2]
print ('\nelements are:\t',num)
count_dict={}
for elements in num:
    count_dict[elements]=num.count(elements)
print ('\nfrequency:\t',count_dict)

2
Si prega di non pubblicare risposte di solo codice ma di chiarire il proprio codice, soprattutto quando una domanda ha già una risposta valida.
Erik,

1
from collections import OrderedDict
a = [1,1,1,1,2,2,2,2,3,3,4,5,5]
def get_count(lists):
    dictionary = OrderedDict()
    for val in lists:
        dictionary.setdefault(val,[]).append(1)
    return [sum(val) for val in dictionary.values()]
print(get_count(a))
>>>[4, 4, 2, 1, 2]

Per rimuovere i duplicati e mantenere l'ordine:

list(dict.fromkeys(get_count(a)))
>>>[4, 2, 1]

1

sto usando Counter per generare una frequenza. dettare dalle parole del file di testo in 1 riga di codice

def _fileIndex(fh):
''' create a dict using Counter of a
flat list of words (re.findall(re.compile(r"[a-zA-Z]+"), lines)) in (lines in file->for lines in fh)
'''
return Counter(
    [wrd.lower() for wrdList in
     [words for words in
      [re.findall(re.compile(r'[a-zA-Z]+'), lines) for lines in fh]]
     for wrd in wrdList])

1

Un altro approccio in tal senso, sebbene utilizzando una libreria più pesante ma potente - NLTK.

import nltk

fdist = nltk.FreqDist(a)
fdist.values()
fdist.most_common()

0

Ancora un'altra soluzione con un altro algoritmo senza usare le raccolte:

def countFreq(A):
   n=len(A)
   count=[0]*n                     # Create a new list initialized with '0'
   for i in range(n):
      count[A[i]]+= 1              # increase occurrence for value A[i]
   return [x for x in count if x]  # return non-zero count

0

È possibile utilizzare la funzione integrata fornita in Python

l.count(l[i])


  d=[]
  for i in range(len(l)):
        if l[i] not in d:
             d.append(l[i])
             print(l.count(l[i])

Il codice sopra rimuove automaticamente i duplicati in un elenco e stampa anche la frequenza di ciascun elemento nell'elenco originale e l'elenco senza duplicati.

Due uccelli per un colpo! XD


0

Questo approccio può essere provato se non si desidera utilizzare alcuna libreria e mantenerlo semplice e breve!

a = [1,1,1,1,2,2,2,2,3,3,4,5,5]
marked = []
b = [(a.count(i), marked.append(i))[0] for i in a if i not in marked]
print(b)

operazione

[4, 4, 2, 1, 2]

0

Per la cronaca, una risposta funzionale:

>>> L = [1,1,1,1,2,2,2,2,3,3,4,5,5]
>>> import functools
>>> >>> functools.reduce(lambda acc, e: [v+(i==e) for i, v in enumerate(acc,1)] if e<=len(acc) else acc+[0 for _ in range(e-len(acc)-1)]+[1], L, [])
[4, 4, 2, 1, 2]

È più pulito se conti anche gli zeri:

>>> functools.reduce(lambda acc, e: [v+(i==e) for i, v in enumerate(acc)] if e<len(acc) else acc+[0 for _ in range(e-len(acc))]+[1], L, [])
[0, 4, 4, 2, 1, 2]

Una spiegazione:

  • iniziamo con un accelenco vuoto ;
  • se l'elemento successivo edi Lè inferiore alla dimensione di acc, aggiorniamo semplicemente questo elemento: v+(i==e)significa v+1se l'indice idi accè l'elemento corrente e, altrimenti il ​​valore precedente v;
  • se l'elemento successivo edi Lè maggiore o uguale alla dimensione di acc, dobbiamo espanderci accper ospitare il nuovo 1.

Gli elementi non devono essere ordinati ( itertools.groupby). Otterrai risultati strani se hai numeri negativi.


0

Ho trovato un altro modo per farlo, usando i set.

#ar is the list of elements
#convert ar to set to get unique elements
sock_set = set(ar)

#create dictionary of frequency of socks
sock_dict = {}

for sock in sock_set:
    sock_dict[sock] = ar.count(sock)

0

Per trovare elementi univoci nell'elenco

a = [1,1,1,1,2,2,2,2,3,3,4,5,5]
a = list(set(a))

Per trovare il conteggio di elementi univoci in una matrice ordinata usando il dizionario

def CountFrequency(my_list): 
# Creating an empty dictionary  
freq = {} 
for item in my_list: 
    if (item in freq): 
        freq[item] += 1
    else: 
        freq[item] = 1

for key, value in freq.items(): 
    print ("% d : % d"%(key, value))

# Driver function 
if __name__ == "__main__":  
my_list =[1, 1, 1, 5, 5, 3, 1, 3, 3, 1, 4, 4, 4, 2, 2, 2, 2] 

CountFrequency(my_list)

Riferimenti GeeksforGeeks


-1

Un altro modo è quello di utilizzare un dizionario e il list.count, sotto un modo ingenuo per farlo.

dicio = dict()

a = [1,1,1,1,2,2,2,2,3,3,4,5,5]

b = list()

c = list()

for i in a:

   if i in dicio: continue 

   else:

      dicio[i] = a.count(i)

      b.append(a.count(i))

      c.append(i)

print (b)

print (c)

-1
a=[1,2,3,4,5,1,2,3]
b=[0,0,0,0,0,0,0]
for i in range(0,len(a)):
    b[a[i]]+=1
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.