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?

mflowww
sumber
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})
ozgur
sumber
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
Aziz Alto
sumber
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()
Gus Hecht
sumber
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
Akavall
sumber
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 
Milind Dumbare
sumber
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
Joel
sumber
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.

CanCeylan
sumber
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()
kata selanjutnya
sumber
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))!

Tidak
sumber
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])?

Anas
sumber
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.

michael
sumber
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.

NaZo
sumber
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
kmario23
sumber
4

Saya akan menggunakan np.where:

how_many_0 = len(np.where(a==0.)[0])
how_many_1 = len(np.where(a==1.)[0])
Maks
sumber
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
Sébastien Wieckowski
sumber
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
sol
sumber
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.

CB Madsen
sumber
2

Coba ini:

a = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])
list(a).count(1)
jarh1992
sumber
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)
pengguna7055304
sumber
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)
Sabeer Ebrahim
sumber
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.

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

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

Dr_Hope
sumber
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
Thomas
sumber
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.

JLT
sumber
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]}
geladak
sumber
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

The Guy
sumber
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 .

norok2
sumber
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
Mauricio Arboleda
sumber
-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.

Ishan Tomar
sumber
bukankah 'sampah' seharusnya nomor?
john ktejik
1
Ya @ johnktejik Anda benar. Jawaban ini tidak berfungsi.
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
sumber
Ada apa dengan tanda dolar di sini?
tripleee