¿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?

mflowww
fuente
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})
ozgur
fuente
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
Aziz Alto
fuente
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()
Gus Hecht
fuente
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
Akavall
fuente
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 
Milind Dumbare
fuente
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
Joel
fuente
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.

CanCeylan
fuente
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()
palabras por el contrario
fuente
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))!

Næreen
fuente
¿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])?

Anas
fuente
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.

Miguel
fuente
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á.

NaZo
fuente
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
kmario23
fuente
4

Yo usaría np.where:

how_many_0 = len(np.where(a==0.)[0])
how_many_1 = len(np.where(a==1.)[0])
MaxG
fuente
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
Sébastien Wieckowski
fuente
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
Sol
fuente
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.

CB Madsen
fuente
2

Prueba esto:

a = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])
list(a).count(1)
jarh1992
fuente
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)
usuario7055304
fuente
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)
Sabeer Ebrahim
fuente
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.

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

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

Dr_Hope
fuente
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
Thomas
fuente
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.

JLT
fuente
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]}
deckard
fuente
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

El tipo
fuente
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í .

norok2
fuente
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
Mauricio Arboleda
fuente
-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.

Ishan Tomar
fuente
¿No se supone que los 'contenedores' son un número?
John Ktejik
1
Sí @johnktejik tienes razón. Esta respuesta no funciona.
Næreen
-1
using numpy.count

$ a = [0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1]

$ np.count(a, 1)
Anggi Permana Harianja
fuente
¿Qué pasa con los signos de dólar aquí?
tripleee