Comment compter l'occurrence de certains éléments dans un ndarray en Python?
En Python, j'ai un ndarray y
qui est imprimé comme array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])
Je suis en train de compter combien de 0
s et combien de 1
s sont là dans ce tableau.
, Mais quand je tape y.count(0)
ou y.count(1)
, dit-il
numpy.ndarray
l'objet n'a pas d'attributcount
Que dois-je faire?
20 réponses
>>> 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}
Non-numpy façon :
Utiliser 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})
Que penser 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
Personnellement, j'irais pour:
(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()
Pour votre cas, vous pouvez également regarder dans 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
Convertissez votre tableau y
en list l
puis faites l.count(1)
et l.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
y = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])
Si vous savez qu'ils sont juste 0
et 1
:
np.sum(y)
Vous Donne le nombre de ceux. np.sum(1-y)
donne les zéros.
Pour une légère généralité, si vous voulez compter 0
et non 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 belle option count
. Dans ce cas, allez dans collections:
import collections
collections.Counter(y)
> Counter({0: 8, 1: 4})
Cela se comporte comme un dict
collections.Counter(y)[0]
> 8
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()
Renvoie combien de fois 2 est survenu dans votre tableau.
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 tromper, si vous l'utilisez avec le booléen comme dans l'exemple, il fera l'affaire.
Honnêtement, je trouve plus facile de convertir en 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 suggéré par Robert Muil:
pd.Series([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1]).value_counts()
J'utiliserais np.où:
how_many_0 = len(np.where(a==0.)[0])
how_many_1 = len(np.where(a==1.)[0])
y.tolist().count(val)
Avec val 0 ou 1
Comme une liste python a une fonction native count
, la conversion en liste avant d'utiliser cette fonction est une solution simple.
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
Personne N'a suggéré d'utiliser numpy.bincount(input, minlength)
avec minlength = np.size(input)
, mais il semble être une bonne solution, et certainement le 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.size(x))
!
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 à l'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
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)
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 aboutirait à 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 dans plusieurs dimensions et que vous voulez compter l'occurrence d'une distribution de valeurs en ligne (=motif 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
Puisque votre ndarray ne contient que 0 et 1, vous pouvez utiliser sum() pour obtenir l'occurrence de 1s et Len () - sum () pour obtenir l'occurrence de 0s.
num_of_ones = sum(array)
num_of_zeros = len(array)-sum(array)
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 de compteur fait presque la même chose mais c'est plus transparent.
Numpy a un module pour cela. Juste un petit hack. Mettez votre tableau d'entrée en tant que bacs.
numpy.histogram(y, bins=y)
Les sorties sont 2 tableaux. L'un avec les valeurs elles-mêmes, l'autre avec les fréquences correspondantes.