Jak policzyć występowanie określonego elementu w ndarray w Pythonie?


376

W Pythonie mam ndarray, y który jest wydrukowany jakoarray([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])

Próbuję policzyć, ile 0s i ile 1jest w tej tablicy.

Ale kiedy piszę y.count(0)lub y.count(1), mówi

numpy.ndarray obiekt nie ma atrybutu count

Co powinienem zrobić?


8
Nie możesz użyć funkcji sumy i długości, ponieważ masz tylko asy i zera?
kodowanie Entuzjasta

W takim przypadku można również po prostu użyć numpy.count_nonzero.
Mong H. Ng

Odpowiedzi:


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}

Sposób nienumeryczny :

Użyj 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
To byłoby `` unikalne, liczy = numpy.unique (a, return_counts = True) dict (zip (unikalny, liczy się)) ''
niszczenie

25
Jeśli chcesz słownika,dict(zip(*numpy.unique(a, return_counts=True)))
Seppo Enarvi 28.04.16

2
Co jeśli chcę uzyskać dostęp do liczby wystąpień każdego unikalnego elementu tablicy bez przypisywania do zmiennej - liczba. Wszelkie wskazówki na ten temat?
sajis997

Mam ten sam cel co @ sajis997. Chcę użyć „count” jako funkcji agregującej w grupie
p_sutherland 15.03.18

1
Próbowałem obu metod dla bardzo dużej tablicy (~ 30 Gb). W metodzie Numpy zabrakło pamięci, podczas gdy collections.Counterzadziałało dobrze
Ivan Novikov,

252

Co z używaniem numpy.count_nonzero, coś takiego

>>> 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
Ta odpowiedź wydaje się lepsza niż ta, która ma najwięcej pozytywnych opinii.
Alex

1
Nie sądzę, żeby to zadziałało, numpy.ndarrayjak pierwotnie poprosił OP.
LYu

5
@LYu - y jest w tym odpowiedzi np. Tablica. Ponadto - większość, jeśli nie wszystkie np. Funkcje coś działają na ndarrays bez problemu.
mmagnuski

132

Osobiście wybrałbym: (y == 0).sum()i(y == 1).sum()

Na przykład

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
Jest to zdecydowanie najłatwiejszy do odczytania. Pytanie, które jest najszybsze i najbardziej zajmujące miejsce
Nathan

Może być mniej zajmujący miejsce niż numpy.count_nonzero (y == 0), ponieważ ocenia wektor (y == 0)
Sridhar Thiagarajan

Lubię to, ponieważ jest podobny do Matlaba / Oktawysum( vector==value )
ePi272314,

39

W twoim przypadku możesz także zajrzeć na 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

Ten kod może być jednym z najszybszych rozwiązań dla większych macierzy, które eksperymentowałem. Uzyskanie wyniku w postaci listy również jest bonusem. Dzięki!
Youngsup Kim

A jeśli „a” jest tablicą n-wymiarową, możemy po prostu użyć: np.bincount (np.reshape (a, a.size))
Ari

21

Konwertuj tablicę yna listę, la następnie wykonaj l.count(1)il.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])

Jeśli wiesz, że są one sprawiedliwe 0i 1:

np.sum(y)

daje liczbę tych. np.sum(1-y)daje zera.

Dla drobnej ogólności, jeśli chcesz liczyć, 0a nie zero (ale prawdopodobnie 2 lub 3):

np.count_nonzero(y)

podaje liczbę niezerową.

Ale jeśli potrzebujesz czegoś bardziej skomplikowanego, nie sądzę, że numpy zapewni dobrą countopcję. W takim przypadku przejdź do kolekcji:

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

To działa jak dyktat

collections.Counter(y)[0]
> 8

13

Jeśli wiesz dokładnie, którego numeru szukasz, możesz użyć następujących;

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

zwraca ile razy 2 wystąpiło w twojej tablicy.


8

Szczerze mówiąc, najłatwiej jest mnie przekonwertować na serię pand lub 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()

Lub ten ładny jednowarstwowy zasugerowany przez Roberta Muila:

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

4
Tylko uwaga: nie potrzebujesz DataFrame ani numpy, możesz przejść bezpośrednio z listy do serii: pd.Series([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1]).value_counts()
Robert Muil

Wspaniale, to fajny jednowarstwowy. Big up
wordsforthewise

8

Nikt nie sugeruje, aby skorzystać numpy.bincount(input, minlength)z minlength = np.size(input), ale wydaje się być dobrym rozwiązaniem i zdecydowanie najszybszy :

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

To szalone przyspieszenie między numpy.unique(x, return_counts=True)i numpy.bincount(x, minlength=np.max(x))!


jak to porównać do histogramu?
john ktejik

@johnktejik np.histogramnie oblicza tego samego. histogramPrzykro mi, nie ma sensu porównywać trzech podejść, które proponuję z funkcją.
Næreen

1
@ Næreen bincountdziała jednak tylko dla liczb całkowitych, więc działa na problem PO, ale może nie na ogólny problem opisany w tytule. Czy próbowałeś także używać bincounttablic z bardzo dużymi intami?
Imperishable Night

@ImperishableNight nie Nie próbowałem z dużymi ints, ale każdy może to zrobić i opublikować własny test porównawczy :-)
Næreen

Dziękujemy za tę niedocenioną sztuczkę! Na moim komputerze bincountjest około cztery razy szybszy niż unique.
Björn Lindqvist


6

y.tolist().count(val)

z wartością 0 lub 1

Ponieważ lista python ma funkcję natywną count, konwersja do listy przed użyciem tej funkcji jest prostym rozwiązaniem.


5

Jeszcze innym prostym rozwiązaniem może być użycie 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

Nie pozwól, aby nazwa wprowadziła cię w błąd, jeśli użyjesz go z wartością logiczną, tak jak w przykładzie, to załatwi sprawę.


5

Aby policzyć liczbę wystąpień, możesz użyć 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

Użyłbym np. Gdzie:

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

3

skorzystaj z metod oferowanych przez serię:

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

Ogólna i prosta odpowiedź brzmiałaby:

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

co w rezultacie dałoby pełny kod

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

Teraz, jeśli MyArray ma wiele wymiarów i chcesz policzyć występowanie rozkładu wartości w linii (= wzór poniżej)

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

Możesz użyć rozumienia słownikowego, aby stworzyć schludny jedno-liniowy. Więcej informacji na temat rozumienia słownika można znaleźć tutaj

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

Spowoduje to utworzenie słownika z wartościami w twoim ndarray jako kluczach i zliczeniami wartości odpowiednio jako wartości kluczy.

Działa to zawsze, gdy chcesz policzyć wystąpienia wartości w tablicach tego formatu.


2

Spróbuj tego:

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

1

Można to łatwo zrobić w następujący sposób

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

1

Ponieważ twoja ndarray zawiera tylko 0 i 1, możesz użyć sum (), aby uzyskać wystąpienie 1s, a len () - sum (), aby uzyskać wystąpienie 0.

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

1

Masz tutaj specjalną tablicę z tylko 1 i 0. Tak więc sztuczka polega na użyciu

np.mean(x)

co daje procent 1s w tablicy. Alternatywnie użyj

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

da ci absolutną liczbę 1 i 0 w twojej tablicy.


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

Właśnie skopiowałem tutaj komentarz Seppo Enarvi, który zasługuje na właściwą odpowiedź


0

Wymaga to jeszcze jednego kroku, ale bardziej elastycznym rozwiązaniem, które działałoby również w przypadku tablic 2D i bardziej skomplikowanych filtrów, jest utworzenie maski logicznej, a następnie użycie .sum () na masce.

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

0

Jeśli nie chcesz używać numpy lub modułu kolekcji, możesz użyć słownika:

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

wynik:

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

Oczywiście możesz także użyć instrukcji if / else. Myślę, że funkcja Licznik robi prawie to samo, ale jest to bardziej przejrzyste.


0

W przypadku wpisów ogólnych:

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

Wyświetli liczbę:

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

I indeksy:

{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

tutaj mam coś, przez co można policzyć liczbę wystąpień określonej liczby: zgodnie z kodem

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

print (liczba_zero)

// zgodnie z dopasowaniem będą wartości logiczne, a zgodnie z wartością True liczba 0 zostanie zwrócona


0

Jeśli jesteś zainteresowany najszybszym wykonaniem, wiesz z góry, jakich wartości szukać, a twoja tablica ma wartość 1D, lub w inny sposób interesuje Cię wynik na spłaszczonej tablicy (w takim przypadku wejście funkcji powinno bądź np.flatten(arr)raczej niż tylko arr), wtedy Numba jest twoim przyjacielem:

import numba as nb


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

lub, w przypadku bardzo dużych tablic, w których równoległość może być korzystna:

@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

Porównywanie ich z np.count_nonzero()(co ma również problem z utworzeniem tymczasowej tablicy, której można uniknąć) i np.unique()oparte na rozwiązaniu

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 

dla danych wejściowych wygenerowanych za pomocą:

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

uzyskiwane są następujące wykresy (drugi rząd wykresów stanowi przybliżenie przy szybszym podejściu):

bm_full bm_zoom

Pokazując, że rozwiązania oparte na Numbie są zauważalnie szybsze niż odpowiedniki NumPy, a przy bardzo dużych nakładach podejście równoległe jest szybsze niż naiwne.


Pełny kod dostępny tutaj .


0

jeśli masz do czynienia z bardzo dużymi tablicami, używanie generatorów może być opcją. Fajne jest to, że to podejście działa dobrze zarówno dla tablic, jak i list, i nie potrzebujesz żadnego dodatkowego pakietu. Ponadto nie używasz tyle pamięci.

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 ma do tego moduł. Tylko mały hack. Umieść tablicę wejściową jako pojemniki.

numpy.histogram(y, bins=y)

Dane wyjściowe to 2 tablice. Jedna z samymi wartościami, druga z odpowiednimi częstotliwościami.


czy „kosze” nie powinny być liczbą?
john ktejik

1
Tak, @johnktejik masz rację. Ta odpowiedź nie działa.
Næreen

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.