¿Cómo contar la aparición de cierto elemento en un ndarray en Python?


376

En Python, tengo un ndarray y que se imprime comoarray([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])

Estoy tratando de contar cuántos 0sy cuántos 1s hay en esta matriz.

Pero cuando escribo y.count(0)o y.count(1), dice

numpy.ndarray el objeto no tiene atributo count

¿Qué tengo que hacer?


8
¿No puedes usar la función de suma y longitud, ya que solo tienes ases y ceros?
codingEntusiasta

En este caso, también es posible simplemente usar numpy.count_nonzero.
Mong H. Ng

Respuestas:


610
>>> a = numpy.array([0, 3, 0, 1, 0, 1, 2, 1, 0, 0, 0, 0, 1, 3, 4])
>>> unique, counts = numpy.unique(a, return_counts=True)
>>> dict(zip(unique, counts))
{0: 7, 1: 4, 2: 1, 3: 2, 4: 1}

Manera no numpy :

Uso collections.Counter;

>> import collections, numpy

>>> a = numpy.array([0, 3, 0, 1, 0, 1, 2, 1, 0, 0, 0, 0, 1, 3, 4])
>>> collections.Counter(a)
Counter({0: 7, 1: 4, 3: 2, 2: 1, 4: 1})

3
Eso sería `` `unique, count = numpy.unique (a, return_counts = True) dict (zip (unique, count))` ``
destrozando el

25
Si quieres el diccionario,dict(zip(*numpy.unique(a, return_counts=True)))
Seppo Enarvi

2
¿Qué sucede si quiero acceder al número de ocurrencias de cada elemento único de la matriz sin asignar a la variable - recuentos? ¿Alguna pista sobre eso?
sajis997

Tengo el mismo objetivo que @ sajis997. Quiero usar 'contar' como una función de agregación en un GroupBy
p_sutherland

1
Intenté usar ambos métodos para una matriz muy grande (~ 30Gb). El método de Numpy se quedó sin memoria mientras que collections.Counterfuncionó bien
Ivan Novikov

252

¿Qué pasa con el uso numpy.count_nonzero, algo como

>>> import numpy as np
>>> y = np.array([1, 2, 2, 2, 2, 0, 2, 3, 3, 3, 0, 0, 2, 2, 0])

>>> np.count_nonzero(y == 1)
1
>>> np.count_nonzero(y == 2)
7
>>> np.count_nonzero(y == 3)
3

20
Esta respuesta parece mejor que la que tiene más votos a favor.
Alex

1
No creo que esto funcione numpy.ndarraycomo OP originalmente pidió.
LYu

55
@LYu: la y es un np.ndarray en esta respuesta. Además, la mayoría, si no todas, las funciones np.something funcionan en ndarrays sin problema.
mmagnuski

132

Personalmente, iría por: (y == 0).sum()y(y == 1).sum()

P.ej

import numpy as np
y = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])
num_zeros = (y == 0).sum()
num_ones = (y == 1).sum()

1
Definitivamente es el más fácil de leer. La pregunta es cuál es el más rápido y el más eficiente en cuanto al espacio
Nathan

Podría ser menos eficiente en espacio que numpy.count_nonzero (y == 0), ya que evalúa el vector (y == 0)
Sridhar Thiagarajan

Me gusta esto porque es similar a matlab / octavasum( vector==value )
ePi272314

39

Para su caso, también puede buscar en numpy.bincount

In [56]: a = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])

In [57]: np.bincount(a)
Out[57]: array([8, 4])  #count of zeros is at index 0 : 8
                        #count of ones is at index 1 : 4

Este código puede ser una de las soluciones más rápidas para matrices más grandes que experimenté. Obtener el resultado como una lista también es una ventaja. Gracias!
Youngsup Kim

Y si 'a' es una matriz n-dimensional, podemos usar: np.bincount (np.reshape (a, a.size))
Ari

21

Convierta su matriz ya la lista ly luego haga l.count(1)yl.count(0)

>>> y = numpy.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])
>>> l = list(y)
>>> l.count(1)
4
>>> l.count(0)
8 

19
y = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])

Si sabes que son justos 0y 1:

np.sum(y)

te da el número de unos. np.sum(1-y)da los ceros.

Para una ligera generalidad, si desea contar 0y no cero (pero posiblemente 2 o 3):

np.count_nonzero(y)

da el número de cero.

Pero si necesita algo más complicado, no creo que numpy le brinde una buena countopción. En ese caso, vaya a colecciones:

import collections
collections.Counter(y)
> Counter({0: 8, 1: 4})

Esto se comporta como un dictado

collections.Counter(y)[0]
> 8

13

Si sabe exactamente qué número está buscando, puede usar lo siguiente;

lst = np.array([1,1,2,3,3,6,6,6,3,2,1])
(lst == 2).sum()

devuelve cuántas veces se produjo 2 en su matriz.


8

Sinceramente, me resulta más fácil convertir a una serie de pandas o un marco de datos:

import pandas as pd
import numpy as np

df = pd.DataFrame({'data':np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])})
print df['data'].value_counts()

O este lindo one-liner sugerido por Robert Muil:

pd.Series([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1]).value_counts()

44
Solo una nota: no necesita el DataFrame o numpy, puede ir directamente de una lista a una Serie: pd.Series([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1]).value_counts()
Robert Muil

Impresionante, esa es una buena frase. Big up
wordsforthewise

8

Nadie sugiere utilizar numpy.bincount(input, minlength)con minlength = np.size(input), pero parece ser una buena solución, y sin duda el más rápido :

In [1]: choices = np.random.randint(0, 100, 10000)

In [2]: %timeit [ np.sum(choices == k) for k in range(min(choices), max(choices)+1) ]
100 loops, best of 3: 2.67 ms per loop

In [3]: %timeit np.unique(choices, return_counts=True)
1000 loops, best of 3: 388 µs per loop

In [4]: %timeit np.bincount(choices, minlength=np.size(choices))
100000 loops, best of 3: 16.3 µs per loop

Esa es una aceleración loca entre numpy.unique(x, return_counts=True)y numpy.bincount(x, minlength=np.max(x))!


¿Cómo se compara con el histograma?
John Ktejik

@johnktejik np.histogramno calcula lo mismo. No tiene sentido comparar los tres enfoques que propongo con la histogramfunción, lo siento.
Næreen

1
Sin bincountembargo, @ Næreen solo funciona para enteros, por lo que funciona para el problema del OP, pero tal vez no para el problema genérico descrito en el título. ¿También has intentado usar bincountcon matrices con entradas muy grandes?
Noche imperecedera

@ImperishableNight no No lo he intentado con grandes ints, pero cualquiera puede hacerlo y publicar su propio punto de referencia :-)
Næreen

¡Gracias por este truco poco apreciado! En mi máquina bincountes aproximadamente cuatro veces más rápido que unique.
Björn Lindqvist

6

¿Qué hay de len(y[y==0])y len(y[y==1])?


6

y.tolist().count(val)

con val 0 o 1

Dado que una lista de Python tiene una función nativa count, la conversión a una lista antes de usar esa función es una solución simple.


5

Otra solución simple podría ser usar numpy.count_nonzero () :

import numpy as np
y = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])
y_nonzero_num = np.count_nonzero(y==1)
y_zero_num = np.count_nonzero(y==0)
y_nonzero_num
4
y_zero_num
8

No dejes que el nombre te confunda, si lo usas con el booleano como en el ejemplo, funcionará.


5

Para contar el número de ocurrencias, puede usar np.unique(array, return_counts=True):

In [75]: boo = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])

# use bool value `True` or equivalently `1`
In [77]: uniq, cnts = np.unique(boo, return_counts=1)
In [81]: uniq
Out[81]: array([0, 1])   #unique elements in input array are: 0, 1

In [82]: cnts
Out[82]: array([8, 4])   # 0 occurs 8 times, 1 occurs 4 times

4

Yo usaría np.where:

how_many_0 = len(np.where(a==0.)[0])
how_many_1 = len(np.where(a==1.)[0])

3

Aproveche los métodos que ofrece una serie:

>>> import pandas as pd
>>> y = [0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1]
>>> pd.Series(y).value_counts()
0    8
1    4
dtype: int64

2

Una respuesta general y simple sería:

numpy.sum(MyArray==x)   # sum of a binary list of the occurence of x (=0 or 1) in MyArray

lo que resultaría en este código completo como ejemplo

import numpy
MyArray=numpy.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])  # array we want to search in
x=0   # the value I want to count (can be iterator, in a list, etc.)
numpy.sum(MyArray==0)   # sum of a binary list of the occurence of x in MyArray

Ahora, si MyArray tiene varias dimensiones y desea contar la ocurrencia de una distribución de valores en línea (= patrón de aquí en adelante)

MyArray=numpy.array([[6, 1],[4, 5],[0, 7],[5, 1],[2, 5],[1, 2],[3, 2],[0, 2],[2, 5],[5, 1],[3, 0]])
x=numpy.array([5,1])   # the value I want to count (can be iterator, in a list, etc.)
temp = numpy.ascontiguousarray(MyArray).view(numpy.dtype((numpy.void, MyArray.dtype.itemsize * MyArray.shape[1])))  # convert the 2d-array into an array of analyzable patterns
xt=numpy.ascontiguousarray(x).view(numpy.dtype((numpy.void, x.dtype.itemsize * x.shape[0])))  # convert what you search into one analyzable pattern
numpy.sum(temp==xt)  # count of the searched pattern in the list of patterns

2

Puede usar la comprensión del diccionario para crear una sola línea ordenada. Puede encontrar más información sobre la comprensión del diccionario aquí.

>>>counts = {int(value): list(y).count(value) for value in set(y)}
>>>print(counts)
{0: 8, 1: 4}

Esto creará un diccionario con los valores en su ndarray como claves, y los recuentos de los valores como los valores para las claves respectivamente.

Esto funcionará siempre que desee contar las ocurrencias de un valor en matrices de este formato.


2

Prueba esto:

a = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])
list(a).count(1)

1

Esto se puede hacer fácilmente en el siguiente método

y = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])
y.tolist().count(1)

1

Como su ndarray contiene solo 0 y 1, puede usar sum () para obtener la ocurrencia de 1s y len () - sum () para obtener la ocurrencia de 0s.

num_of_ones = sum(array)
num_of_zeros = len(array)-sum(array)

1

Tienes una matriz especial con solo 1 y 0 aquí. Entonces, un truco es usar

np.mean(x)

que le da el porcentaje de 1s en su matriz. Alternativamente, use

np.sum(x)
np.sum(1-x)

le dará el número absoluto de 1 y 0 en su matriz.


1
dict(zip(*numpy.unique(y, return_counts=True)))

Acabo de copiar el comentario de Seppo Enarvi aquí que merece ser una respuesta adecuada


0

Implica un paso más, pero una solución más flexible que también funcionaría para matrices 2d y filtros más complicados es crear una máscara booleana y luego usar .sum () en la máscara.

>>>>y = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])
>>>>mask = y == 0
>>>>mask.sum()
8

0

Si no desea usar numpy o un módulo de colecciones, puede usar un diccionario:

d = dict()
a = [0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1]
for item in a:
    try:
        d[item]+=1
    except KeyError:
        d[item]=1

resultado:

>>>d
{0: 8, 1: 4}

Por supuesto, también puede usar una instrucción if / else. Creo que la función de contador hace casi lo mismo, pero esto es más transparente.


0

Para entradas genéricas:

x = np.array([11, 2, 3, 5, 3, 2, 16, 10, 10, 3, 11, 4, 5, 16, 3, 11, 4])
n = {i:len([j for j in np.where(x==i)[0]]) for i in set(x)}
ix = {i:[j for j in np.where(x==i)[0]] for i in set(x)}

Producirá un recuento:

{2: 2, 3: 4, 4: 2, 5: 2, 10: 2, 11: 3, 16: 2}

E índices:

{2: [1, 5],
3: [2, 4, 9, 14],
4: [11, 16],
5: [3, 12],
10: [7, 8],
11: [0, 10, 15],
16: [6, 13]}

0

Aquí tengo algo, a través del cual puede contar el número de ocurrencias de un número particular: de acuerdo con su código

count_of_zero = list (y [y == 0]). count (0)

print (cuenta_de_cero)

// según la coincidencia habrá valores booleanos y según el valor verdadero se devolverá el número 0


0

Si está interesado en la ejecución más rápida, sabe de antemano qué valores buscar y su matriz es 1D, o le interesa el resultado en la matriz aplanada (en cuyo caso, la entrada de la función debería ser en np.flatten(arr)lugar de solo arr), entonces Numba es tu amiga:

import numba as nb


@nb.jit
def count_nb(arr, value):
    result = 0
    for x in arr:
        if x == value:
            result += 1
    return result

o, para matrices muy grandes donde la paralelización puede ser beneficiosa:

@nb.jit(parallel=True)
def count_nbp(arr, value):
    result = 0
    for i in nb.prange(arr.size):
        if arr[i] == value:
            result += 1
    return result

Comparación de estos contra np.count_nonzero()(que también tiene un problema de crear una matriz temporal que se puede evitar) y una np.unique()solución basada

import numpy as np


def count_np(arr, value):
    return np.count_nonzero(arr == value)
import numpy as np


def count_np2(arr, value):
    uniques, counts = np.unique(a, return_counts=True)
    counter = dict(zip(uniques, counts))
    return counter[value] if value in counter else 0 

para entrada generada con:

def gen_input(n, a=0, b=100):
    return np.random.randint(a, b, n)

se obtienen los siguientes gráficos (la segunda fila de gráficos es un zoom en el enfoque más rápido):

bm_full bm_zoom

Mostrando que la solución basada en Numba es notablemente más rápida que las contrapartes de NumPy y, para entradas muy grandes, el enfoque paralelo es más rápido que el ingenuo.


Código completo disponible aquí .


0

Si se trata de matrices muy grandes con generadores podría ser una opción. Lo bueno aquí es que este enfoque funciona bien tanto para matrices como para listas y no necesita ningún paquete adicional. Además, no está utilizando tanta memoria.

my_array = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])
sum(1 for val in my_array if val==0)
Out: 8

-1

Numpy tiene un módulo para esto. Solo un pequeño truco. Ponga su matriz de entrada como contenedores.

numpy.histogram(y, bins=y)

La salida son 2 matrices. Uno con los valores en sí, otro con las frecuencias correspondientes.


¿No se supone que los 'contenedores' son un número?
John Ktejik

1
Sí @johnktejik tienes razón. Esta respuesta no funciona.
Næreen

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.