Bagaimana cara menghitung kemunculan item tertentu dalam ndarray di Python?


376

Dalam Python, saya memiliki ndarray y yang dicetak sebagaiarray([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])

Saya mencoba untuk menghitung berapa banyak 0dan berapa banyak 1yang ada dalam array ini.

Tetapi ketika saya mengetik y.count(0)atau y.count(1), katanya

numpy.ndarray objek tidak memiliki atribut count

Apa yang harus saya lakukan?


8
Tidak bisakah kamu menggunakan fungsi penjumlahan dan panjang, karena kamu hanya memiliki ace dan nol?
codingEnthusiast

Dalam hal ini, dimungkinkan juga untuk hanya menggunakan numpy.count_nonzero.
Mong H. Ng

Jawaban:


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}

Cara non-numpy :

Gunakan 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
Itu akan menjadi `` `unik, counts = numpy.unique (a, return_counts = True) dict (zip (unik, jumlah))` ``
merobek

25
Jika Anda menginginkan kamus,dict(zip(*numpy.unique(a, return_counts=True)))
Seppo Enarvi

2
Bagaimana jika saya ingin mengakses jumlah kemunculan dari setiap elemen unik dari array tanpa menugaskan ke variabel - jumlah. Ada petunjuk tentang itu?
sajis997

Saya memiliki tujuan yang sama dengan @ sajis997. Saya ingin menggunakan 'menghitung' sebagai fungsi agregasi dalam groupby
p_sutherland

1
Mencoba menggunakan kedua metode untuk array yang sangat besar (~ 30Gb). Metode numpy kehabisan memori sedangkan yang collections.Counterbekerja dengan baik
Ivan Novikov

252

Bagaimana dengan menggunakan numpy.count_nonzero, sesuatu seperti

>>> 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
Jawaban ini tampaknya lebih baik daripada jawaban dengan suara terbanyak.
Alex

1
Saya tidak berpikir ini akan berhasil karena numpy.ndarrayOP awalnya bertanya.
LYu

5
@LYu - y adalah np.ndarray dalam jawaban ini. Juga - sebagian besar jika tidak semua fungsi np.sesuatu berfungsi pada ndarrays tanpa masalah.
mmagnuski

132

Secara pribadi, saya akan pergi untuk: (y == 0).sum()dan(y == 1).sum()

Misalnya

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
Ini pasti yang paling mudah dibaca. Pertanyaannya adalah mana yang tercepat, dan paling hemat ruang
Nathan

Mungkin lebih hemat ruang daripada numpy.count_nonzero (y == 0), karena mengevaluasi vektor (y == 0)
Sridhar Thiagarajan

Saya suka ini karena mirip dengan matlab / oktafsum( vector==value )
ePi272314

39

Untuk kasus Anda, Anda juga bisa melihat 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

Kode ini mungkin merupakan salah satu solusi tercepat untuk array yang lebih besar yang saya coba. Mendapatkan hasilnya sebagai daftar juga merupakan bonus. Terima kasih!
Youngsup Kim

Dan jika 'a' adalah array n-dimensional, kita bisa menggunakan: np.bincount (np.reshape (a, a.size))
Ari

21

Konversikan array Anda ymenjadi daftar llalu lakukan l.count(1)danl.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])

Jika Anda tahu bahwa mereka adil 0dan 1:

np.sum(y)

memberi Anda jumlah yang. np.sum(1-y)memberikan nol.

Untuk sedikit generalisasi, jika Anda ingin menghitung 0dan bukan nol (tetapi mungkin 2 atau 3):

np.count_nonzero(y)

memberikan angka bukan nol.

Tetapi jika Anda membutuhkan sesuatu yang lebih rumit, saya tidak berpikir numpy akan memberikan countopsi yang bagus . Dalam hal ini, buka koleksi:

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

Ini berperilaku seperti dict

collections.Counter(y)[0]
> 8

13

Jika Anda tahu persis nomor yang Anda cari, Anda dapat menggunakan yang berikut ini;

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

mengembalikan berapa kali 2 terjadi dalam array Anda.


8

Jujur saya merasa paling mudah untuk mengonversi ke Seri panda atau 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()

Atau satu kalimat yang disarankan oleh Robert Muil:

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

4
Hanya sebuah catatan: tidak perlu DataFrame atau numpy, bisa langsung dari daftar ke Seri: pd.Series([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1]).value_counts()
Robert Muil

Luar biasa, itu bagus sekali. Besar
kata

8

Tidak ada yang menyarankan untuk menggunakan numpy.bincount(input, minlength)dengan minlength = np.size(input), tetapi tampaknya menjadi solusi yang baik, dan pasti tercepat :

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

Itu percepatan gila antara numpy.unique(x, return_counts=True)dan numpy.bincount(x, minlength=np.max(x))!


bagaimana itu dibandingkan dengan histogram?
john ktejik

@ johnktejik np.histogramtidak menghitung hal yang sama. Tidak ada gunanya membandingkan tiga pendekatan yang saya usulkan dengan histogramfungsi, maaf.
Næreen

1
@Næreen bincounthanya bekerja untuk bilangan bulat, jadi itu berfungsi untuk masalah OP, tapi mungkin tidak untuk masalah umum yang dijelaskan dalam judul. Anda juga sudah mencoba menggunakan bincountdengan array dengan int yang sangat besar?
Imperishable Night

@ImperishableNight no Saya belum mencoba dengan int besar, tapi siapa pun
boleh

Terima kasih atas trik yang kurang dihargai ini! Di komputer saya bincountsekitar empat kali lebih cepat daripada unique.
Björn Lindqvist

6

Bagaimana dengan len(y[y==0])dan len(y[y==1])?


6

y.tolist().count(val)

dengan val 0 atau 1

Karena daftar python memiliki fungsi asli count, mengonversi ke daftar sebelum menggunakan fungsi itu adalah solusi sederhana.


5

Namun solusi sederhana lain mungkin menggunakan 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

Jangan biarkan namanya menyesatkan Anda, jika Anda menggunakannya dengan boolean seperti dalam contoh, itu akan melakukan trik.


5

Untuk menghitung jumlah kejadian, Anda dapat menggunakan 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

Saya akan menggunakan np.where:

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

3

manfaatkan metode yang ditawarkan oleh 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

Jawaban umum dan sederhana adalah:

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

yang akan menghasilkan kode lengkap ini sebagai contoh

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

Sekarang jika MyArray berada dalam beberapa dimensi dan Anda ingin menghitung kemunculan distribusi nilai dalam garis (= pola selanjutnya)

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

Anda dapat menggunakan pemahaman kamus untuk membuat one-liner yang rapi. Lebih lanjut tentang pemahaman kamus dapat ditemukan di sini

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

Ini akan membuat kamus dengan nilai-nilai di ndarray Anda sebagai kunci, dan jumlah nilai sebagai nilai untuk kunci masing-masing.

Ini akan berfungsi kapan pun Anda ingin menghitung kemunculan nilai dalam larik format ini.


2

Coba ini:

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

1

Ini dapat dilakukan dengan mudah dalam metode berikut

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

1

Karena ndarray Anda hanya berisi 0 dan 1, Anda dapat menggunakan sum () untuk mendapatkan kemunculan 1s dan len () - sum () untuk mendapatkan kemunculan 0s.

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

1

Anda memiliki larik khusus dengan hanya 1 dan 0 di sini. Jadi triknya adalah menggunakan

np.mean(x)

yang memberi Anda persentase 1 dalam array Anda. Atau, gunakan

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

akan memberi Anda angka absolut 1 dan 0 dalam array Anda.


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

Hanya menyalin komentar Seppo Enarvi di sini yang pantas menjadi jawaban yang tepat


0

Ini melibatkan satu langkah lagi, tetapi solusi yang lebih fleksibel yang juga akan bekerja untuk array 2d dan filter yang lebih rumit adalah membuat topeng boolean dan kemudian menggunakan .sum () pada topeng.

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

0

Jika Anda tidak ingin menggunakan modul numpy atau koleksi, Anda dapat menggunakan kamus:

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

hasil:

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

Tentu saja Anda juga dapat menggunakan pernyataan if / else. Saya pikir fungsi Penghitung melakukan hal yang hampir sama tetapi ini lebih transparan.


0

Untuk entri umum:

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

Akan menampilkan hitungan:

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

Dan indeks:

{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

di sini saya memiliki sesuatu, di mana Anda dapat menghitung jumlah kemunculan nomor tertentu: sesuai dengan kode Anda

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

print (count_of_zero)

// menurut pertandingan akan ada nilai boolean dan menurut nilai True angka 0 akan kembali


0

Jika Anda tertarik dengan eksekusi tercepat, Anda tahu sebelumnya nilai mana yang harus dicari, dan array Anda adalah 1D, atau Anda sebaliknya tertarik pada hasil pada array yang rata (dalam hal ini input fungsi harus menjadi np.flatten(arr)lebih dari adil arr), maka Numba adalah teman Anda:

import numba as nb


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

atau, untuk array yang sangat besar di mana paralelisasi mungkin bermanfaat:

@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

Benchmarking ini terhadap np.count_nonzero()(yang juga memiliki masalah membuat array sementara yang dapat dihindari) dan np.unique()solusi berbasis

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 

untuk input yang dihasilkan dengan:

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

plot berikut diperoleh (baris kedua plot adalah zoom pada pendekatan yang lebih cepat):

bm_full bm_zoom

Menunjukkan bahwa solusi berbasis Numba terasa lebih cepat daripada rekan NumPy, dan, untuk input yang sangat besar, pendekatan paralelnya lebih cepat daripada yang naif.


Kode lengkap tersedia di sini .


0

jika Anda berurusan dengan array yang sangat besar menggunakan generator bisa menjadi pilihan. Yang menyenangkan di sini adalah bahwa pendekatan ini berfungsi baik untuk array dan daftar dan Anda tidak memerlukan paket tambahan. Selain itu, Anda tidak menggunakan banyak memori.

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 memiliki modul untuk ini. Hanya hack kecil. Masukkan array input Anda sebagai nampan.

numpy.histogram(y, bins=y)

Outputnya adalah 2 array. Satu dengan nilai-nilai itu sendiri, yang lain dengan frekuensi yang sesuai.


bukankah 'sampah' seharusnya nomor?
john ktejik

1
Ya @ johnktejik Anda benar. Jawaban ini tidak berfungsi.
Næreen

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.