¿Cómo contar la frecuencia de los elementos en una lista desordenada?


237

Necesito encontrar la frecuencia de los elementos en una lista desordenada

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

salida->

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

También quiero eliminar los duplicados de un

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

¿Siempre se ordenan como en ese ejemplo?
Farinha

@Peter. Sí, ha ordenado la lista para fines de publicación. ¿La lista siempre estará ordenada?
S.Lott

2
No, la lista no se ordenará siempre. Esto no es tarea.
Bruce

Estoy tratando de trazar el gráfico de distribución de grados de una red.
Bruce

55
@ Peter: Actualice su pregunta con la información útil. No agregue comentarios a su pregunta: usted es el propietario de la pregunta, puede arreglarla para que sea completa y clara.
S.Lott

Respuestas:


147

Nota: Debe ordenar la lista antes de usar groupby.

Se puede utilizar groupbyde itertoolspaquete si la lista es una lista ordenada.

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

Salida:

[4, 4, 2, 1, 2]

agradable, usando groupby. Sin embargo, me pregunto acerca de su eficiencia frente al enfoque dict
Eli Bendersky,

32
Python groupby crea nuevos grupos cuando cambia el valor que ve. En este caso 1,1,1,2,1,1,1] devolvería [3,1,3]. Si esperaba [6,1], asegúrese de ordenar los datos antes de usar groupby.
Evan

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

66
Esta no es una solución. La salida no dice lo que se contó.
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

532

En Python 2.7 (o más reciente), puede usar 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)]

Si está utilizando Python 2.6 o anterior, puede descargarlo aquí .


1
@unutbu: ¿Qué sucede si tengo tres listas, a, b, c para las cuales ayb siguen siendo las mismas, pero c cambia? ¿Cómo contar el valor de c para el cual ayc son iguales?
ThePredator

@Srivatsan: No entiendo la situación. Por favor, publique una nueva pregunta donde pueda elaborar.
unutbu

1
¿Hay alguna forma de extraer el diccionario {1: 4, 2: 4, 3: 2, 5: 2, 4: 1} del objeto contador?
Pavan

77
@Pavan: collections.Counteres una subclase de dict. Puede usarlo de la misma manera que lo haría con un dict normal. Sin embargo, si realmente quieres un dict, puedes convertirlo a un dict usando dict(counter).
unutbu

1
Trabaja en 3.6 también, por lo que suponen algo más grande que 2,7
kpierce8

108

Python 2.7+ presenta la comprensión del diccionario. Construir el diccionario a partir de la lista le dará el recuento y eliminará los duplicados.

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

Esto funciona muy bien con listas de cadenas en lugar de números enteros como la pregunta original formulada.
Glen Selle

15
Es más rápido usar un conjunto:{x:a.count(x) for x in set(a)}
stenci

45
Esto es enormemente ineficiente . a.count()realiza un recorrido completo para cada elemento en a, haciendo de este un enfoque cuadrádico O (N ^ 2). collections.Counter()es mucho más eficiente porque cuenta en tiempo lineal (O (N)). En números, esto significa que este enfoque se ejecutarán 1 millón de pasos para una lista de longitud 1000, frente a sólo 1.000 pasos con Counter(), 10 ^ 12 pasos, donde sólo el 10 ^ 6 son necesarios por el contador por un millón de elementos de una lista, etc.
Martijn Pieters

3
@stenci: claro, pero el horror de usar a.count()completamente eclipsa la eficiencia de haber usado un set allí.
Martijn Pieters

2
@MartijnPieters una razón más para usarlo menos veces :)
stenci

48

Para contar el número de apariciones:

from collections import defaultdict

appearances = defaultdict(int)

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

Para eliminar duplicados:

a = set(a) 

1
+1 para colecciones.defaultdict. Además, en python 3.x, busque colecciones. Es lo mismo que collections.defaultdict (int).
hughdbrown

2
@hughdbrown, en realidad Counterpuede usar múltiples tipos numéricos, incluidos floato Decimalno solo int.
Cristian Ciupitu

28

En Python 2.7+, puede usar colecciones. Contador para contar elementos

>>> 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
El contador es mucho más lento que el dict predeterminado, y el dict predeterminado es mucho más lento que el uso manual de un dict.
Jonathan Ray


25

Contar la frecuencia de los elementos probablemente se haga mejor con un diccionario:

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

Para eliminar los duplicados, use un conjunto:

a = list(set(a))

3
@phkahler: El mío sería solo un poquito mejor que esto. No vale la pena publicar una respuesta por separado cuando esto se puede mejorar con un pequeño cambio. El objetivo de SO es llegar a las mejores respuestas. Simplemente podría editar esto, pero prefiero permitirle al autor original la oportunidad de hacer sus propias mejoras.
S.Lott

1
@ S.Lott El código es mucho más limpio sin tener que importar defaultdict.
bstrauch24

¿Por qué no preinicializar b b = {k:0 for k in a}:?
DylanYoung

20

Aquí hay otra alternativa sucinta itertools.groupbyque también funciona para entradas no ordenadas:

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

resultados

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

16

Puedes hacerlo:

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

Salida:

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

La primera matriz son valores, y la segunda matriz es el número de elementos con estos valores.

Entonces, si desea obtener solo una matriz con los números, debe usar esto:

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

Si bien este fragmento de código puede ser la solución, incluir una explicación realmente ayuda a mejorar la calidad de su publicación. Recuerde que está respondiendo la pregunta para los lectores en el futuro, y esas personas podrían no saber las razones de su sugerencia de código
Rahul Gupta

Sí lo hará Rahul Gupta
Anirban Lahiri

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

44
el uso de listas countes ridículamente costoso y no se requiere en este escenario.
Idan K

@IdanK, ¿por qué contar es caro?
Kritika Rajain

@KritikaRajain Para cada elemento único en la lista, itera sobre toda la lista para generar un recuento (cuadrático en el número de elementos únicos en la lista). En su lugar, puede iterar sobre la lista una vez y contar el número de cada elemento único (lineal en el tamaño de la lista). Si su lista tiene solo un elemento único, el resultado será el mismo. Además, este enfoque requiere un conjunto intermedio adicional.
DylanYoung


4

Para su primera pregunta, repita la lista y use un diccionario para realizar un seguimiento de la existencia de un elemento.

Para su segunda pregunta, solo use el operador set.


44
¿Puedes por favor dar más detalles sobre la primera respuesta
Bruce

3

Esta respuesta es más explícita.

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

Llego bastante tarde, pero esto también funcionará y ayudará a otros:

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

producirá esto ...

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 colección de conjuntos no permite duplicados, pasar una lista al constructor set () dará un iterable de objetos totalmente únicos. La función count () devuelve una cuenta entera cuando se pasa un objeto que está en una lista. Con eso, los objetos únicos se cuentan y cada valor de conteo se almacena agregando a una salida de lista vacía
  2. El constructor list () se utiliza para convertir el conjunto (a) en una lista y se hace referencia por la misma variable a

Salida

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

2

Solución simple usando un diccionario.

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())no cambiará en el último bucle. No lo calcules en el ciclo, cómpralo antes 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
No publique respuestas de solo código, pero aclare su código, especialmente cuando una pregunta ya tiene una respuesta válida.
Erik A

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]

Para eliminar duplicados y mantener el orden:

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

1

Estoy usando Counter para generar una frecuencia. dict de palabras de archivo de texto en 1 línea de código

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

Otro enfoque para hacer esto, aunque mediante el uso de una biblioteca más pesada pero poderosa, NLTK.

import nltk

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

0

Otra solución más con otro algoritmo sin usar colecciones:

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

Puede usar la función integrada proporcionada en 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])

El código anterior elimina automáticamente los duplicados en una lista y también imprime la frecuencia de cada elemento en la lista original y la lista sin duplicados.

¡Dos pájaros para un disparo! XD


0

¡Este enfoque se puede probar si no desea utilizar ninguna biblioteca y mantenerla simple y 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)

o / p

[4, 4, 2, 1, 2]

0

Para el registro, una respuesta funcional:

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

Es más limpio si también cuentas ceros:

>>> 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 explicación:

  • comenzamos con una acclista vacía ;
  • si el siguiente elemento ede Les menor que el tamaño de acc, simplemente actualizamos este elemento: v+(i==e)significa v+1si el índice ide acces el elemento actual e, de lo contrario, el valor anterior v;
  • Si el siguiente elemento ede Les mayor o igual al tamaño de acc, tenemos que expandirnos accpara alojar el nuevo 1.

Los elementos no tienen que ser ordenados ( itertools.groupby). Obtendrás resultados extraños si tienes números negativos.


0

Encontré otra forma de hacerlo, usando conjuntos.

#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

Para encontrar elementos únicos en la lista

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

Para encontrar el recuento de elementos únicos en una matriz ordenada usando el diccionario

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)

GeeksforGeeks de referencia


-1

Una forma más es usar un diccionario y list.count, debajo de una forma ingenua de hacerlo.

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.