Wie zähle ich das Auftreten eines bestimmten Elements in einem ndarray in Python?


376

In Python habe ich ein ndarray y , das als gedruckt wirdarray([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])

Ich versuche zu zählen, wie viele 0s und wie viele 1s in diesem Array vorhanden sind.

Aber wenn ich tippe y.count(0)oder y.count(1), heißt es

numpy.ndarray Objekt hat kein Attribut count

Was sollte ich tun?


8
Können Sie die Summen- und Längenfunktion nicht verwenden, da Sie nur Asse und Nullen haben?
CodierungEnthusiast

In diesem Fall ist es auch möglich, einfach zu verwenden numpy.count_nonzero.
Mong H. Ng

Antworten:


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}

Nicht numpy Weg :

Verwenden Sie 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
Das wäre `` `einzigartig, count = numpy.unique (a, return_counts = True) dict (zip (einzigartig, zählt))` ``
Shredding

25
Wenn Sie das Wörterbuch wollen,dict(zip(*numpy.unique(a, return_counts=True)))
Seppo Enarvi

2
Was ist, wenn ich auf die Anzahl der Vorkommen der einzelnen eindeutigen Elemente des Arrays zugreifen möchte, ohne die Variablenanzahl zuzuweisen? Irgendwelche Hinweise dazu?
sajis997

Ich habe das gleiche Ziel wie @ sajis997. Ich möchte 'count' als Aggregationsfunktion in einer Gruppe verwenden
p_sutherland

1
Versucht mit beiden Methoden für ein sehr großes Array (~ 30Gb). Numpy Methode ging der Speicher aus, während die gut collections.Counterfunktionierte
Ivan Novikov

252

Was ist mit so numpy.count_nonzeroetwas wie

>>> 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
Diese Antwort scheint besser zu sein als die mit den meisten positiven Stimmen.
Alex

1
Ich denke nicht, dass dies funktionieren würde, numpy.ndarraywie OP ursprünglich gefragt hatte.
LYu

5
@LYu - das y ist ein np.ndarray in dieser Antwort. Auch - die meisten, wenn nicht alle np.something-Funktionen funktionieren problemlos auf ndarrays.
mmagnuski

132

Persönlich würde ich gehen für: (y == 0).sum()und(y == 1).sum()

Z.B

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
Es ist definitiv am einfachsten zu lesen. Die Frage ist, welche am schnellsten und am platzsparendsten ist
Nathan

Möglicherweise weniger platzsparend als numpy.count_nonzero (y == 0), da der Vektor (y == 0) ausgewertet wird
Sridhar Thiagarajan

Ich mag das, weil es ähnlich wie Matlab / Oktave istsum( vector==value )
ePi272314

39

Für Ihren Fall können Sie auch in numpy.bincount nachsehen

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

Dieser Code ist möglicherweise eine der schnellsten Lösungen für größere Arrays, die ich experimentiert habe. Das Ergebnis als Liste zu erhalten, ist ebenfalls ein Bonus. Danke!
Youngsup Kim

Und wenn 'a' ein n-dimensionales Array ist, können wir einfach verwenden: np.bincount (np.reshape (a, a.size))
Ari

21

Konvertieren Sie Ihr Array yin eine Liste lund führen Sie dann l.count(1)und ausl.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])

Wenn Sie wissen, dass sie gerecht sind 0und 1:

np.sum(y)

gibt Ihnen die Anzahl der Einsen. np.sum(1-y)gibt die Nullen.

Für eine leichte Allgemeinheit, wenn Sie zählen möchten 0und nicht Null (aber möglicherweise 2 oder 3):

np.count_nonzero(y)

gibt die Anzahl ungleich Null an.

Aber wenn Sie etwas Komplizierteres brauchen, denke ich nicht, dass Numpy eine gute countOption ist. In diesem Fall gehen Sie zu Sammlungen:

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

Das verhält sich wie ein Diktat

collections.Counter(y)[0]
> 8

13

Wenn Sie genau wissen, nach welcher Nummer Sie suchen, können Sie Folgendes verwenden:

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

Gibt zurück, wie oft 2 in Ihrem Array aufgetreten ist.


8

Ehrlich gesagt finde ich es am einfachsten, in eine Pandas-Serie oder einen DataFrame zu konvertieren:

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

Oder dieser nette Einzeiler von Robert Muil:

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

4
Nur eine Anmerkung: Benötigen Sie nicht den DataFrame oder Numpy, können Sie direkt von einer Liste zu einer Serie wechseln: pd.Series([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1]).value_counts()
Robert Muil

Super, das ist ein schöner Einzeiler. Big up
Worte für den

8

Niemand schlug vor, numpy.bincount(input, minlength)mit zu verwenden minlength = np.size(input), aber es scheint eine gute Lösung zu sein und definitiv die schnellste :

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

Das ist eine verrückte Beschleunigung zwischen numpy.unique(x, return_counts=True)und numpy.bincount(x, minlength=np.max(x))!


Wie ist es mit dem Histogramm zu vergleichen?
John Ktejik

@johnktejik np.histogramberechnet nicht dasselbe. Es macht keinen Sinn, die drei von mir vorgeschlagenen Ansätze mit der histogramFunktion zu vergleichen.
Næreen

1
@ Næreen bincountfunktioniert zwar nur für Ganzzahlen, daher für das OP-Problem, möglicherweise jedoch nicht für das im Titel beschriebene generische Problem. Haben Sie auch versucht, bincountmit Arrays mit sehr großen Ints zu arbeiten?
Unverderbliche Nacht

@ImperishableNight nein, ich habe es nicht mit großen Ints versucht, aber jeder kann dies tun und seinen eigenen Benchmark veröffentlichen :-)
Næreen

Vielen Dank für diesen unterschätzten Trick! Auf meiner Maschine bincountist etwa viermal schneller als unique.
Björn Lindqvist

6

Was ist mit len(y[y==0])und len(y[y==1])?


6

y.tolist().count(val)

mit Wert 0 oder 1

Da eine Python-Liste eine native Funktion hat count, ist die Konvertierung in eine Liste vor Verwendung dieser Funktion eine einfache Lösung.


5

Eine weitere einfache Lösung könnte darin bestehen, numpy.count_nonzero () zu verwenden :

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

Lassen Sie sich nicht vom Namen irreführen. Wenn Sie ihn wie im Beispiel mit dem Booleschen Wert verwenden, reicht er aus.


5

Um die Anzahl der Vorkommen zu zählen, können Sie Folgendes verwenden 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

Ich würde np.where verwenden:

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

3

Nutzen Sie die Methoden einer 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

Eine allgemeine und einfache Antwort wäre:

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

was beispielsweise zu diesem vollständigen Code führen würde

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

Wenn MyArray nun mehrere Dimensionen hat und Sie das Auftreten einer Werteverteilung in einer Linie zählen möchten (= Muster im Folgenden)

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

Sie können das Wörterbuchverständnis verwenden, um einen ordentlichen Einzeiler zu erstellen. Weitere Informationen zum Wörterbuchverständnis finden Sie hier

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

Dadurch wird ein Wörterbuch mit den Werten in Ihrem ndarray als Schlüssel und der Anzahl der Werte als Werte für die Schlüssel erstellt.

Dies funktioniert immer dann, wenn Sie Vorkommen eines Werts in Arrays dieses Formats zählen möchten.


2

Versuche dies:

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

1

Dies kann auf einfache Weise mit der folgenden Methode durchgeführt werden

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

1

Da Ihr ndarray nur 0 und 1 enthält, können Sie sum () verwenden, um das Auftreten von 1s zu ermitteln, und len () - sum (), um das Auftreten von 0s zu ermitteln.

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

1

Sie haben hier ein spezielles Array mit nur 1 und 0. Ein Trick ist also zu benutzen

np.mean(x)

Dies gibt Ihnen den Prozentsatz von 1s in Ihrem Array. Alternativ verwenden

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

gibt Ihnen die absolute Zahl 1 und 0 in Ihrem Array.


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

Ich habe gerade den Kommentar von Seppo Enarvi hier kopiert, der eine richtige Antwort verdient


0

Es ist ein weiterer Schritt erforderlich, aber eine flexiblere Lösung, die auch für 2D-Arrays und kompliziertere Filter funktioniert, besteht darin, eine Boolesche Maske zu erstellen und dann .sum () für die Maske zu verwenden.

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

0

Wenn Sie numpy oder ein Sammlungsmodul nicht verwenden möchten, können Sie ein Wörterbuch verwenden:

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

Ergebnis:

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

Natürlich können Sie auch eine if / else-Anweisung verwenden. Ich denke, die Zählerfunktion macht fast das Gleiche, aber das ist transparenter.


0

Für generische Einträge:

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

Gibt eine Zählung aus:

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

Und Indizes:

{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

Hier habe ich etwas, anhand dessen Sie die Häufigkeit des Auftretens einer bestimmten Zahl zählen können: gemäß Ihrem Code

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

print (count_of_zero)

// Entsprechend der Übereinstimmung gibt es boolesche Werte und gemäß dem True-Wert wird die Zahl 0 zurückgegeben


0

Wenn Sie an der schnellsten Ausführung interessiert sind, wissen Sie im Voraus, nach welchen Werten Sie suchen müssen, und Ihr Array ist 1D, oder Sie interessieren sich anderweitig für das Ergebnis auf dem abgeflachten Array (in diesem Fall sollte die Eingabe der Funktion erfolgen sei np.flatten(arr)eher als nur arr), dann ist Numba dein Freund:

import numba as nb


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

oder für sehr große Arrays, bei denen Parallelisierung vorteilhaft sein kann:

@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

Vergleich dieser np.count_nonzero()(was auch das Problem hat, ein temporäres Array zu erstellen, das vermieden werden kann) und np.unique()basierter Lösung

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 

für Eingaben generiert mit:

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

Die folgenden Diagramme werden erhalten (die zweite Diagrammreihe ist ein Zoom auf den schnelleren Ansatz):

bm_full bm_zoom

Dies zeigt, dass Numba-basierte Lösungen spürbar schneller sind als die NumPy-Gegenstücke, und bei sehr großen Eingaben ist der parallele Ansatz schneller als der naive.


Vollständiger Code hier verfügbar .


0

Wenn Sie mit sehr großen Arrays arbeiten, die Generatoren verwenden, kann dies eine Option sein. Das Schöne daran ist, dass dieser Ansatz sowohl für Arrays als auch für Listen gut funktioniert und Sie kein zusätzliches Paket benötigen. Außerdem verwenden Sie nicht so viel Speicher.

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 hat dafür ein Modul. Nur ein kleiner Hack. Legen Sie Ihr Eingabearray als Bins ab.

numpy.histogram(y, bins=y)

Die Ausgabe sind 2 Arrays. Einer mit den Werten selbst, der andere mit den entsprechenden Frequenzen.


Soll 'Mülleimer' nicht eine Zahl sein?
John Ktejik

1
Ja @johnktejik du hast recht. Diese Antwort funktioniert nicht .
Næreen

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.