Comment compter l'occurrence de certains éléments dans un ndarray en Python?

376

En Python, j'ai un ndarray y qui est imprimé commearray([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])

J'essaie de compter combien de 0s et combien il y a de 1s dans ce tableau.

Mais quand je tape y.count(0)ou y.count(1), ça dit

numpy.ndarray l'objet n'a pas d'attribut count

Que devrais-je faire?

mflowww
la source
8
Ne pouvez-vous pas utiliser la fonction somme et longueur, car vous n'avez que des as et des zéros?
codingEnthusiast
Dans ce cas, il est également possible d'utiliser simplement numpy.count_nonzero.
Mong H. Ng

Réponses:

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}

Manière non numpy :

Utilisation 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
la source
3
Ce serait `` `` unique, count = numpy.unique (a, return_counts = True) dict (zip (unique, count)) ``
déchiquetage
25
Si vous voulez le dictionnaire,dict(zip(*numpy.unique(a, return_counts=True)))
Seppo Enarvi
2
Que faire si je veux accéder au nombre d'occurrences de chaque élément unique du tableau sans attribuer à la variable - count. Des indices à ce sujet?
sajis997
J'ai le même objectif que @ sajis997. Je veux utiliser 'count' comme fonction d'agrégation dans un groupby
p_sutherland
1
Essayé en utilisant les deux méthodes pour un très grand tableau (~ 30 Go). La méthode Numpy a manqué de mémoire alors que cela collections.Counterfonctionnait très bien
Ivan Novikov
252

Qu'en est-il de l'utilisation numpy.count_nonzero, quelque chose comme

>>> 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
la source
20
Cette réponse semble meilleure que celle avec le plus de votes positifs.
Alex
1
Je ne pense pas que cela fonctionnerait numpy.ndarraycomme OP l'avait demandé à l'origine.
LYu
5
@LYu - le y est un np.ndarray dans cette réponse. Aussi - la plupart sinon toutes les fonctions de np.something fonctionnent sur les ndarrays sans problème.
mmagnuski
132

Personnellement, je choisirais: (y == 0).sum()et(y == 1).sum()

Par exemple

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
la source
1
C'est certainement le plus facile à lire. La question est de savoir laquelle est la plus rapide et la plus économe en espace
Nathan
Peut être moins économe en espace que numpy.count_nonzero (y == 0), car il évalue le vecteur (y == 0)
Sridhar Thiagarajan
J'aime ça parce que c'est similaire à matlab / octavesum( vector==value )
ePi272314
39

Pour votre cas, vous pouvez également consulter 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
la source
Ce code peut être l'une des solutions les plus rapides pour les tableaux plus grands que j'ai expérimentés. Obtenir le résultat sous forme de liste est également un bonus. Merci!
Youngsup Kim
Et si 'a' est un tableau à n dimensions, nous pouvons simplement utiliser: np.bincount (np.reshape (a, a.size))
Ari
21

Convertissez votre tableau yen liste l, puis faites l.count(1)etl.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
la source
19
y = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])

Si vous savez qu'ils sont justes 0et 1:

np.sum(y)

vous en donne le nombre. np.sum(1-y)donne les zéros.

Pour une généralité légère, si vous voulez compter 0et non pas zéro (mais éventuellement 2 ou 3):

np.count_nonzero(y)

donne le nombre de non nul.

Mais si vous avez besoin de quelque chose de plus compliqué, je ne pense pas que numpy fournira une bonne countoption. Dans ce cas, accédez aux collections:

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

Cela se comporte comme un dicton

collections.Counter(y)[0]
> 8
Joel
la source
13

Si vous savez exactement quel numéro vous recherchez, vous pouvez utiliser ce qui suit;

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

retourne combien de fois 2 s'est produit dans votre tableau.

CanCeylan
la source
8

Honnêtement, je trouve qu'il est plus facile de convertir une série pandas ou DataFrame:

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

Ou ce joli one-liner proposé par Robert Muil:

pd.Series([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1]).value_counts()
mots dans le sens
la source
4
Juste une note: pas besoin de DataFrame ou numpy, peut aller directement d'une liste à une série: pd.Series([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1]).value_counts()
Robert Muil
Génial, c'est une belle doublure. Big up
wordsforthewise
8

Personne n'a suggéré d'utiliser numpy.bincount(input, minlength)avec minlength = np.size(input), mais cela semble être une bonne solution, et certainement la plus rapide :

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

C'est une accélération folle entre numpy.unique(x, return_counts=True)et numpy.bincount(x, minlength=np.max(x))!

Næreen
la source
comment comparer avec l'histogramme?
john ktejik
@johnktejik np.histogramne calcule pas la même chose. Inutile de comparer les trois approches que je propose avec la histogramfonction, désolé.
Næreen
1
@ Næreen bincountne fonctionne que pour les entiers, donc cela fonctionne pour le problème de l'OP, mais peut-être pas pour le problème générique décrit dans le titre. Avez-vous également essayé d'utiliser bincountdes tableaux avec de très gros pouces?
Nuit impérissable du
@ImperishableNight non, je n'ai pas essayé avec de gros pouces, mais tout le monde est invité à le faire et à publier son propre benchmark :-)
Næreen
Merci pour cette astuce sous-estimée! Sur ma machine bincountest environ quatre fois plus rapide que unique.
Björn Lindqvist
6

Et pour len(y[y==0])et len(y[y==1])?

Anas
la source
6

y.tolist().count(val)

avec val 0 ou 1

Étant donné qu'une liste python a une fonction native count, la conversion en liste avant d'utiliser cette fonction est une solution simple.

Michael
la source
5

Encore une autre solution simple pourrait être d'utiliser 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

Ne laissez pas le nom vous induire en erreur, si vous l'utilisez avec le booléen comme dans l'exemple, il fera l'affaire.

NaZo
la source
5

Pour compter le nombre d'occurrences, vous pouvez utiliser 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
la source
4

J'utiliserais np.where:

how_many_0 = len(np.where(a==0.)[0])
how_many_1 = len(np.where(a==1.)[0])
MaxG
la source
3

profitez des méthodes offertes par une Série:

>>> 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
la source
2

Une réponse générale et simple serait:

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

qui résulterait en ce code complet comme exemple

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

Maintenant, si MyArray est en plusieurs dimensions et que vous souhaitez compter l'occurrence d'une distribution de valeurs en ligne (= modèle ci-après)

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
la source
2

Vous pouvez utiliser la compréhension du dictionnaire pour créer une ligne nette soignée. Pour en savoir plus sur la compréhension du dictionnaire, cliquez ici

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

Cela créera un dictionnaire avec les valeurs de votre ndarray sous forme de clés et le nombre de valeurs comme valeurs pour les clés respectivement.

Cela fonctionnera chaque fois que vous souhaitez compter les occurrences d'une valeur dans des tableaux de ce format.

CB Madsen
la source
2

Essaye ça:

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

Cela peut être fait facilement dans la méthode suivante

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

Puisque votre ndarray ne contient que 0 et 1, vous pouvez utiliser sum () pour obtenir l'occurrence de 1 et len ​​() - sum () pour obtenir l'occurrence de 0.

num_of_ones = sum(array)
num_of_zeros = len(array)-sum(array)
Sabeer Ebrahim
la source
1

Vous avez un tableau spécial avec seulement 1 et 0 ici. Donc, une astuce consiste à utiliser

np.mean(x)

ce qui vous donne le pourcentage de 1 dans votre tableau. Vous pouvez également utiliser

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

vous donnera le nombre absolu de 1 et 0 dans votre tableau.

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

Je viens de copier ici le commentaire de Seppo Enarvi qui mérite d'être une bonne réponse

Dr_Hope
la source
0

Cela implique une étape de plus, mais une solution plus flexible qui fonctionnerait également pour les tableaux 2D et les filtres plus compliqués consiste à créer un masque booléen, puis à utiliser .sum () sur le masque.

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

Si vous ne voulez pas utiliser numpy ou un module de collections, vous pouvez utiliser un dictionnaire:

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

résultat:

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

Bien sûr, vous pouvez également utiliser une instruction if / else. Je pense que la fonction Counter fait presque la même chose mais c'est plus transparent.

JLT
la source
0

Pour les entrées génériques:

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

Sortira un décompte:

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

Et les indices:

{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
la source
0

ici j'ai quelque chose, à travers lequel vous pouvez compter le nombre d'occurrence d'un nombre particulier: selon votre code

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

imprimer (count_of_zero)

// selon la correspondance, il y aura des valeurs booléennes et selon la valeur True, le nombre 0 sera retourné

Le mec
la source
0

Si vous êtes intéressé par l'exécution la plus rapide, vous savez à l'avance quelle (s) valeur (s) rechercher, et votre tableau est 1D, ou vous êtes autrement intéressé par le résultat sur le tableau aplati (auquel cas l'entrée de la fonction devrait être np.flatten(arr)plutôt que juste arr), alors Numba est votre ami:

import numba as nb


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

ou, pour les très grands tableaux où la parallélisation peut être bénéfique:

@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

Analyse comparative de ceux-ci np.count_nonzero()(qui a également un problème de création d'un tableau temporaire qui peut être évité) et d'une np.unique()solution basée sur

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 

pour les entrées générées avec:

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

les tracés suivants sont obtenus (la deuxième rangée de tracés est un zoom sur l'approche la plus rapide):

bm_full bm_zoom

Montrant que la solution basée sur Numba est sensiblement plus rapide que ses homologues NumPy, et, pour de très grandes entrées, l'approche parallèle est plus rapide que la naïve.


Code complet disponible ici .

norok2
la source
0

si vous avez affaire à de très grands tableaux utilisant des générateurs, cela pourrait être une option. La bonne chose ici, c'est que cette approche fonctionne bien pour les tableaux et les listes et vous n'avez pas besoin de package supplémentaire. En outre, vous n'utilisez pas autant de mémoire.

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
la source
-1

Numpy a un module pour cela. Juste un petit hack. Mettez votre tableau d'entrée sous forme de bacs.

numpy.histogram(y, bins=y)

La sortie est constituée de 2 tableaux. L'un avec les valeurs elles-mêmes, l'autre avec les fréquences correspondantes.

Ishan Tomar
la source
les «bacs» ne sont-ils pas censés être un nombre?
john ktejik
1
Oui @johnktejik, vous avez raison. Cette réponse ne fonctionne pas .
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
la source
Quel est le signe du dollar ici?
tripleee