¿Cómo puedo contar las ocurrencias de un elemento de la lista?


1530

Dado un elemento, ¿cómo puedo contar sus ocurrencias en una lista en Python?

Respuestas:


1853

Si solo desea el recuento de un elemento, use el countmétodo:

>>> [1, 2, 3, 4, 1, 4, 1].count(1)
3

No use esto si desea contar varios elementos. Las llamadas counten bucle requieren un pase separado sobre la lista para cada countllamada, lo que puede ser catastrófico para el rendimiento. Si desea contar todos los elementos, o incluso solo varios, use Counter, como se explica en las otras respuestas.


66
mylist = [1,7,7,7,3,9,9,9,7,9,10,0] print sorted(set([i for i in mylist if mylist.count(i)>2]))
cpp-coder

1747

Úselo Countersi está utilizando Python 2.7 o 3.xy desea el número de ocurrencias para cada elemento:

>>> from collections import Counter
>>> z = ['blue', 'red', 'blue', 'yellow', 'blue', 'red']
>>> Counter(z)
Counter({'blue': 3, 'red': 2, 'yellow': 1})

2
He encontrado que cuando uso esto mucho (hablando de millones de cadenas) es muy lento debido a sus llamadas a isinstance. Entonces, si está seguro de los datos con los que está trabajando, podría ser mejor escribir una función personalizada sin verificación de tipo e instancia.
Bram Vanroy

2
@BramVanroy: ¿Qué isinstancellamadas? Incluso con millones de cadenas, llamar Countersolo implica una isinstancellamada, para verificar si su argumento es un mapeo. Lo más probable es que hayas juzgado mal lo que está comiendo todo tu tiempo.
user2357112 es compatible con Monica el

Interpretaste mal lo que quise decir: Counter verifica los tipos de datos antes de crear el Counter. Esto lleva relativamente mucho tiempo y si conoce el tipo de sus datos de antemano. Si observa el método de actualización de Counter, verá que tiene que pasar por tres declaraciones if antes de hacer algo. Si llama a la actualización con frecuencia, esto se suma rápidamente. Cuando tenga control sobre sus datos y sepa que la entrada será de hecho iterable, puede omitir las dos primeras verificaciones. Como dije, solo noté esto cuando trabajé con millones de actualizaciones, por lo que es un caso extremo.
Bram Vanroy

2
@BramVanroy: si está realizando millones de actualizaciones en lugar de contar millones de cadenas, esa es una historia diferente. El esfuerzo de optimización se Counterha llevado a contar grandes iterables, en lugar de contar muchos iterables. Contar un iterativo de un millón de cadenas será más rápido Counterque con una implementación manual. Si desea llamar updatecon muchos iterables, puede acelerar las cosas uniéndolas en un solo iterable itertools.chain.
user2357112 es compatible con Monica el

262

Contando las ocurrencias de un artículo en una lista

Para contar las ocurrencias de un solo elemento de la lista, puede usar count()

>>> l = ["a","b","b"]
>>> l.count("a")
1
>>> l.count("b")
2

Contar las ocurrencias de todos los elementos de una lista también se conoce como "contar" una lista o crear un contador de conteo.

Contando todos los artículos con count ()

Para contar las ocurrencias de los elementos en luno, simplemente puede usar una lista de comprensión y el count()método

[[x,l.count(x)] for x in set(l)]

(o de manera similar con un diccionario dict((x,l.count(x)) for x in set(l)))

Ejemplo:

>>> l = ["a","b","b"]
>>> [[x,l.count(x)] for x in set(l)]
[['a', 1], ['b', 2]]
>>> dict((x,l.count(x)) for x in set(l))
{'a': 1, 'b': 2}

Contando todos los artículos con Counter ()

Alternativamente, está la Counterclase más rápida de la collectionsbiblioteca.

Counter(l)

Ejemplo:

>>> l = ["a","b","b"]
>>> from collections import Counter
>>> Counter(l)
Counter({'b': 2, 'a': 1})

¿Cuánto más rápido es Counter?

Verifiqué cuánto más rápido Counteres para las listas de conteo. Probé ambos métodos con algunos valores de ny parece que Counteres más rápido en un factor constante de aproximadamente 2.

Aquí está el script que usé:

from __future__ import print_function
import timeit

t1=timeit.Timer('Counter(l)', \
                'import random;import string;from collections import Counter;n=1000;l=[random.choice(string.ascii_letters) for x in range(n)]'
                )

t2=timeit.Timer('[[x,l.count(x)] for x in set(l)]',
                'import random;import string;n=1000;l=[random.choice(string.ascii_letters) for x in range(n)]'
                )

print("Counter(): ", t1.repeat(repeat=3,number=10000))
print("count():   ", t2.repeat(repeat=3,number=10000)

Y la salida:

Counter():  [0.46062711701961234, 0.4022796869976446, 0.3974247490405105]
count():    [7.779430688009597, 7.962715800967999, 8.420845870045014]

32
Counteres mucho más rápido para listas más grandes. El método de comprensión de la lista es O (n ^ 2), Counterdebe ser O (n).
fhucho

20
El contador no es más rápido por un factor de 2, el contador es más rápido por un factor de n (O (n ^ 2) vs O (n)).
Martijn Pieters

He encontrado que cuando uso esto mucho (hablando de millones de cadenas) es muy lento debido a sus llamadas a isinstance. Entonces, si está seguro de los datos con los que está trabajando, podría ser mejor escribir una función personalizada sin verificación de tipo e instancia.
Bram Vanroy

66

Otra forma de obtener el número de ocurrencias de cada elemento, en un diccionario:

dict((i, a.count(i)) for i in a)

49
Esto parece una de las construcciones que a menudo se me ocurre en el fragor de la batalla, pero se ejecutará a través de len (a) veces, lo que significa complejidad de tiempo de ejecución cuadrático (ya que cada ejecución depende de len (a) nuevamente).
Nicolas78

55
¿dict ((i, a.count (i)) para i en el conjunto (a)) sería más correcto y más rápido?
hugo24

66
@ hugo24: Un poco, pero no será asintóticamente más rápido en el peor de los casos; Tomará n * (number of different items)operaciones, sin contar el tiempo que lleva construir el conjunto. Usar collections.Counteres realmente mucho mejor.
Clément

muy tarde para la fiesta, pero el siguiente código no arrojaría un error si una lista contuviera más de una instancia i, porque intentará ingresar múltiples claves del mismo valor en un diccionario. dict((i, a.count(i)) for i in a)
rp1


45

Dado un elemento, ¿cómo puedo contar sus ocurrencias en una lista en Python?

Aquí hay una lista de ejemplos:

>>> l = list('aaaaabbbbcccdde')
>>> l
['a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'e']

list.count

Ahí está el list.countmétodo

>>> l.count('b')
4

Esto funciona bien para cualquier lista. Las tuplas también tienen este método:

>>> t = tuple('aabbbffffff')
>>> t
('a', 'a', 'b', 'b', 'b', 'f', 'f', 'f', 'f', 'f', 'f')
>>> t.count('f')
6

collections.Counter

Y luego están las colecciones. Contador. Puede volcar cualquier iterable en un Contador, no solo una lista, y el Contador retendrá una estructura de datos de los recuentos de los elementos.

Uso:

>>> from collections import Counter
>>> c = Counter(l)
>>> c['b']
4

Los contadores se basan en diccionarios de Python, sus claves son los elementos, por lo que las claves deben ser hashaable. Básicamente son como conjuntos que permiten elementos redundantes en ellos.

Uso adicional de collections.Counter

Puede sumar o restar con iterables de su contador:

>>> c.update(list('bbb'))
>>> c['b']
7
>>> c.subtract(list('bbb'))
>>> c['b']
4

Y también puede realizar operaciones de conjuntos múltiples con el contador:

>>> c2 = Counter(list('aabbxyz'))
>>> c - c2                   # set difference
Counter({'a': 3, 'c': 3, 'b': 2, 'd': 2, 'e': 1})
>>> c + c2                   # addition of all elements
Counter({'a': 7, 'b': 6, 'c': 3, 'd': 2, 'e': 1, 'y': 1, 'x': 1, 'z': 1})
>>> c | c2                   # set union
Counter({'a': 5, 'b': 4, 'c': 3, 'd': 2, 'e': 1, 'y': 1, 'x': 1, 'z': 1})
>>> c & c2                   # set intersection
Counter({'a': 2, 'b': 2})

¿Por qué no pandas?

Otra respuesta sugiere:

¿Por qué no usar pandas?

Pandas es una biblioteca común, pero no está en la biblioteca estándar. Agregarlo como un requisito no es trivial.

Hay soluciones integradas para este caso de uso en el objeto de lista en sí, así como en la biblioteca estándar.

Si su proyecto aún no requiere pandas, sería una tontería exigirlo solo para esta funcionalidad.


44
Si bien "por qué no Pandas" es apropiado, probablemente debería ir acompañado de "cuándo usar NumPy", es decir, para matrices numéricas grandes. El factor decisivo no es solo las limitaciones del proyecto, hay eficiencias de memoria con NumPy que se hacen evidentes con Big Data.
jpp

Gracias por mencionar Pandas / etc como una dependencia seria. Algunos de estos paquetes tienen efectos secundarios negativos. Por lo tanto, la adición de estos activos para necesidades triviales puede costar mucho tiempo y $. Personalmente, he experimentado que Numpy y SciPi agregaron 30 minutos a nuestra cartera de CI y me tomó días obtener el almacenamiento en caché del paquete correctamente. Grandes paquetes, pero a veces hay gastos ocultos. +1
Marc

36

Comparé todas las soluciones sugeridas (y algunas nuevas) con perfplot (un pequeño proyecto mío).

Contando un artículo

Para matrices lo suficientemente grandes, resulta que

numpy.sum(numpy.array(a) == 1) 

es un poco más rápido que las otras soluciones.

ingrese la descripción de la imagen aquí

Contando todos los artículos

Como se estableció anteriormente ,

numpy.bincount(a)

es lo que quieres

ingrese la descripción de la imagen aquí


Código para reproducir las tramas:

from collections import Counter
from collections import defaultdict
import numpy
import operator
import pandas
import perfplot


def counter(a):
    return Counter(a)


def count(a):
    return dict((i, a.count(i)) for i in set(a))


def bincount(a):
    return numpy.bincount(a)


def pandas_value_counts(a):
    return pandas.Series(a).value_counts()


def occur_dict(a):
    d = {}
    for i in a:
        if i in d:
            d[i] = d[i]+1
        else:
            d[i] = 1
    return d


def count_unsorted_list_items(items):
    counts = defaultdict(int)
    for item in items:
        counts[item] += 1
    return dict(counts)


def operator_countof(a):
    return dict((i, operator.countOf(a, i)) for i in set(a))


perfplot.show(
    setup=lambda n: list(numpy.random.randint(0, 100, n)),
    n_range=[2**k for k in range(20)],
    kernels=[
        counter, count, bincount, pandas_value_counts, occur_dict,
        count_unsorted_list_items, operator_countof
        ],
    equality_check=None,
    logx=True,
    logy=True,
    )

2)

from collections import Counter
from collections import defaultdict
import numpy
import operator
import pandas
import perfplot


def counter(a):
    return Counter(a)


def count(a):
    return dict((i, a.count(i)) for i in set(a))


def bincount(a):
    return numpy.bincount(a)


def pandas_value_counts(a):
    return pandas.Series(a).value_counts()


def occur_dict(a):
    d = {}
    for i in a:
        if i in d:
            d[i] = d[i]+1
        else:
            d[i] = 1
    return d


def count_unsorted_list_items(items):
    counts = defaultdict(int)
    for item in items:
        counts[item] += 1
    return dict(counts)


def operator_countof(a):
    return dict((i, operator.countOf(a, i)) for i in set(a))


perfplot.show(
    setup=lambda n: list(numpy.random.randint(0, 100, n)),
    n_range=[2**k for k in range(20)],
    kernels=[
        counter, count, bincount, pandas_value_counts, occur_dict,
        count_unsorted_list_items, operator_countof
        ],
    equality_check=None,
    logx=True,
    logy=True,
    )

77
numpy.bincount () funcionará solo para listas con elementos int.
Mukarram Pasha

35

Si desea contar todos los valores a la vez , puede hacerlo muy rápido utilizando matrices numpy y de la bincountsiguiente manera

import numpy as np
a = np.array([1, 2, 3, 4, 1, 4, 1])
np.bincount(a)

lo que da

>>> array([0, 3, 1, 1, 2])

19

Si puede usar pandas, entonces value_countsestá allí para rescatarlo.

>>> import pandas as pd
>>> a = [1, 2, 3, 4, 1, 4, 1]
>>> pd.Series(a).value_counts()
1    3
4    2
3    1
2    1
dtype: int64

También clasifica automáticamente el resultado según la frecuencia.

Si desea que el resultado esté en una lista de la lista, haga lo siguiente

>>> pd.Series(a).value_counts().reset_index().values.tolist()
[[1, 3], [4, 2], [3, 1], [2, 1]]

pandas tiene muchos gastos generales, por lo que es la solución más lenta con pequeñas cantidades de datos. stackoverflow.com/a/46195192/125507
endolito

14

¿Por qué no usar pandas?

import pandas as pd

l = ['a', 'b', 'c', 'd', 'a', 'd', 'a']

# converting the list to a Series and counting the values
my_count = pd.Series(l).value_counts()
my_count

Salida:

a    3
d    2
b    1
c    1
dtype: int64

Si está buscando un conteo de un elemento en particular, diga a , intente:

my_count['a']

Salida:

3

13

Tuve este problema hoy y lancé mi propia solución antes de pensar en comprobar SO. Esta:

dict((i,a.count(i)) for i in a)

es muy, muy lento para listas grandes. Mi solución

def occurDict(items):
    d = {}
    for i in items:
        if i in d:
            d[i] = d[i]+1
        else:
            d[i] = 1
return d

en realidad es un poco más rápido que la solución Counter, al menos para Python 2.7.


1
Contador ordena las entradas mientras suyo no lo hace, por lo tanto, la diferencia de velocidad (. Es cierto que en el momento de escribir esto, no estoy seguro si fue cuando escribió la respuesta embargo, podría ser relevante para alguien que desplazarse hacia abajo.)
chaosflaws

3
El contador en Python 2 fue un poco lento, sí. Sin embargo, utiliza un código C optimizado para hacer el recuento en Python 3, y ahora supera tu ciclo con facilidad.
Martijn Pieters

12
# Python >= 2.6 (defaultdict) && < 2.7 (Counter, OrderedDict)
from collections import defaultdict
def count_unsorted_list_items(items):
    """
    :param items: iterable of hashable items to count
    :type items: iterable

    :returns: dict of counts like Py2.7 Counter
    :rtype: dict
    """
    counts = defaultdict(int)
    for item in items:
        counts[item] += 1
    return dict(counts)


# Python >= 2.2 (generators)
def count_sorted_list_items(items):
    """
    :param items: sorted iterable of items to count
    :type items: sorted iterable

    :returns: generator of (item, count) tuples
    :rtype: generator
    """
    if not items:
        return
    elif len(items) == 1:
        yield (items[0], 1)
        return
    prev_item = items[0]
    count = 1
    for item in items[1:]:
        if prev_item == item:
            count += 1
        else:
            yield (prev_item, count)
            count = 1
            prev_item = item
    yield (item, count)
    return


import unittest
class TestListCounters(unittest.TestCase):
    def test_count_unsorted_list_items(self):
        D = (
            ([], []),
            ([2], [(2,1)]),
            ([2,2], [(2,2)]),
            ([2,2,2,2,3,3,5,5], [(2,4), (3,2), (5,2)]),
            )
        for inp, exp_outp in D:
            counts = count_unsorted_list_items(inp) 
            print inp, exp_outp, counts
            self.assertEqual(counts, dict( exp_outp ))

        inp, exp_outp = UNSORTED_WIN = ([2,2,4,2], [(2,3), (4,1)])
        self.assertEqual(dict( exp_outp ), count_unsorted_list_items(inp) )


    def test_count_sorted_list_items(self):
        D = (
            ([], []),
            ([2], [(2,1)]),
            ([2,2], [(2,2)]),
            ([2,2,2,2,3,3,5,5], [(2,4), (3,2), (5,2)]),
            )
        for inp, exp_outp in D:
            counts = list( count_sorted_list_items(inp) )
            print inp, exp_outp, counts
            self.assertEqual(counts, exp_outp)

        inp, exp_outp = UNSORTED_FAIL = ([2,2,4,2], [(2,3), (4,1)])
        self.assertEqual(exp_outp, list( count_sorted_list_items(inp) ))
        # ... [(2,2), (4,1), (2,1)]

2
@plaes: ¿Cómo es eso? Si por 'empresarial', quiere decir "documentado" en preparación para las anotaciones Py3k, estoy de acuerdo.
Wes Turner

1
Este es un gran ejemplo, ya que estoy desarrollando principalmente en 2.7, pero tengo que tener rutas de migración a 2.4.
Adam Lewis

9

A continuación se presentan las tres soluciones:

Lo más rápido es usar un bucle for y almacenarlo en un Dict.

import time
from collections import Counter


def countElement(a):
    g = {}
    for i in a:
        if i in g: 
            g[i] +=1
        else: 
            g[i] =1
    return g


z = [1,1,1,1,2,2,2,2,3,3,4,5,5,234,23,3,12,3,123,12,31,23,13,2,4,23,42,42,34,234,23,42,34,23,423,42,34,23,423,4,234,23,42,34,23,4,23,423,4,23,4]


#Solution 1 - Faster
st = time.monotonic()
for i in range(1000000):
    b = countElement(z)
et = time.monotonic()
print(b)
print('Simple for loop and storing it in dict - Duration: {}'.format(et - st))

#Solution 2 - Fast
st = time.monotonic()
for i in range(1000000):
    a = Counter(z)
et = time.monotonic()
print (a)
print('Using collections.Counter - Duration: {}'.format(et - st))

#Solution 3 - Slow
st = time.monotonic()
for i in range(1000000):
    g = dict([(i, z.count(i)) for i in set(z)])
et = time.monotonic()
print(g)
print('Using list comprehension - Duration: {}'.format(et - st))

Resultado

#Solution 1 - Faster
{1: 4, 2: 5, 3: 4, 4: 6, 5: 2, 234: 3, 23: 10, 12: 2, 123: 1, 31: 1, 13: 1, 42: 5, 34: 4, 423: 3}
Simple for loop and storing it in dict - Duration: 12.032000000000153
#Solution 2 - Fast
Counter({23: 10, 4: 6, 2: 5, 42: 5, 1: 4, 3: 4, 34: 4, 234: 3, 423: 3, 5: 2, 12: 2, 123: 1, 31: 1, 13: 1})
Using collections.Counter - Duration: 15.889999999999418
#Solution 3 - Slow
{1: 4, 2: 5, 3: 4, 4: 6, 5: 2, 34: 4, 423: 3, 234: 3, 42: 5, 12: 2, 13: 1, 23: 10, 123: 1, 31: 1}
Using list comprehension - Duration: 33.0

9

Recuento de todos los elementos con itertools.groupby()

Otra posibilidad para obtener el recuento de todos los elementos de la lista podría ser mediante itertools.groupby().

Con recuentos "duplicados"

from itertools import groupby

L = ['a', 'a', 'a', 't', 'q', 'a', 'd', 'a', 'd', 'c']  # Input list

counts = [(i, len(list(c))) for i,c in groupby(L)]      # Create value-count pairs as list of tuples 
print(counts)

Devoluciones

[('a', 3), ('t', 1), ('q', 1), ('a', 1), ('d', 1), ('a', 1), ('d', 1), ('c', 1)]

Observe cómo combinó los primeros tres acomo el primer grupo, mientras que otros grupos aestán presentes más abajo en la lista. Esto sucede porque la lista de entrada Lno se ordenó. Esto puede ser un beneficio a veces si los grupos deberían estar separados.

Con recuentos únicos

Si se desean recuentos de grupos únicos, simplemente ordene la lista de entrada:

counts = [(i, len(list(c))) for i,c in groupby(sorted(L))]
print(counts)

Devoluciones

[('a', 5), ('c', 1), ('d', 2), ('q', 1), ('t', 1)]

Nota: Para crear recuentos únicos, muchas de las otras respuestas proporcionan un código más fácil y más legible en comparación con la groupbysolución. Pero se muestra aquí para dibujar un paralelo al ejemplo de conteo duplicado.


7

Se sugirió usar el bincount de numpy , sin embargo, solo funciona para matrices 1d con enteros no negativos . Además, la matriz resultante puede ser confusa (contiene las ocurrencias de los enteros de mínimo a máximo de la lista original, y establece en 0 los enteros faltantes).

Una mejor manera de hacerlo con numpy es usar la función única con el atributo return_countsestablecido en True. Devuelve una tupla con una matriz de valores únicos y una matriz de las ocurrencias de cada valor único.

# a = [1, 1, 0, 2, 1, 0, 3, 3]
a_uniq, counts = np.unique(a, return_counts=True)  # array([0, 1, 2, 3]), array([2, 3, 1, 2]

y luego podemos emparejarlos como

dict(zip(a_uniq, counts))  # {0: 2, 1: 3, 2: 1, 3: 2}

También funciona con otros tipos de datos y "listas 2d", p. Ej.

>>> a = [['a', 'b', 'b', 'b'], ['a', 'c', 'c', 'a']]
>>> dict(zip(*np.unique(a, return_counts=True)))
{'a': 3, 'b': 3, 'c': 2}

6

Para contar la cantidad de elementos diversos que tienen un tipo común:

li = ['A0','c5','A8','A2','A5','c2','A3','A9']

print sum(1 for el in li if el[0]=='A' and el[1] in '01234')

da

3 no 6



3

También puede usar el countOfmétodo de un módulo incorporado operator.

>>> import operator
>>> operator.countOf([1, 2, 3, 4, 1, 4, 1], 1)
3

1
¿Cómo countOfse implementa? ¿Cómo se compara con lo más obvio list.count(que se beneficia de la implementación de C)? ¿Hay alguna ventaja?
Chris_Rands

2

Puede no ser el más eficiente, requiere un pase adicional para eliminar duplicados.

Implementación funcional:

arr = np.array(['a','a','b','b','b','c'])
print(set(map(lambda x  : (x , list(arr).count(x)) , arr)))

devoluciones :

{('c', 1), ('b', 3), ('a', 2)}

o volver como dict:

print(dict(map(lambda x  : (x , list(arr).count(x)) , arr)))

devoluciones :

{'b': 3, 'c': 1, 'a': 2}

1
sum([1 for elem in <yourlist> if elem==<your_value>])

Esto devolverá la cantidad de ocurrencias de your_value


1

Yo usaría filter(), tome el ejemplo de Lukasz:

>>> lst = [1, 2, 3, 4, 1, 4, 1]
>>> len(filter(lambda x: x==1, lst))
3

0

si desea una serie de ocurrencias para el elemento en particular:

>>> from collections import Counter
>>> z = ['blue', 'red', 'blue', 'yellow', 'blue', 'red']
>>> single_occurrences = Counter(z)
>>> print(single_occurrences.get("blue"))
3
>>> print(single_occurrences.values())
dict_values([3, 2, 1])

-1
def countfrequncyinarray(arr1):
    r=len(arr1)
    return {i:arr1.count(i) for i in range(1,r+1)}
arr1=[4,4,4,4]
a=countfrequncyinarray(arr1)
print(a)

3
Si bien este código puede responder la pregunta, proporcionar un contexto adicional con respecto a por qué y / o cómo responde la pregunta mejora su valor a largo plazo.
Alex Riabov

-1
l2=[1,"feto",["feto",1,["feto"]],['feto',[1,2,3,['feto']]]]
count=0
 def Test(l):   
        global count 
        if len(l)==0:
             return count
        count=l.count("feto")
        for i in l:
             if type(i) is list:
                count+=Test(i)
        return count   
    print(Test(l2))

esto contará recursivamente o buscará el elemento en la lista incluso si está en la lista de listas


no sé por qué alguien acaba de votar una respuesta y es completamente útil
Mohamed Fathallah
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.