Python'da bir ndarray'de belirli öğelerin oluşumunu nasıl sayabilirim?


376

Python'da y şu şekilde basılmış bir ndarray var:array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])

Bu dizide kaç tane 0s ve kaç tane 1s olduğunu saymaya çalışıyorum .

Ama yazarken y.count(0)veya y.count(1)diyor,

numpy.ndarray nesnenin özelliği yok count

Ne yapmalıyım?


8
Yalnızca as ve sıfırlarınız olduğu için toplam ve uzunluk işlevlerini kullanamaz mısınız?
codingEnthusiast

Bu durumda, sadece kullanmak da mümkündür numpy.count_nonzero.
Mong H. Ng

Yanıtlar:


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}

Numpy olmayan yol :

Kullanın 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
Bu `` benzersiz, sayımlar = numpy.unique (a, return_counts = True) dict (zip (benzersiz, sayımlar)) ``
parçalama

25
Sözlük istiyorsanız,dict(zip(*numpy.unique(a, return_counts=True)))
Seppo Enarvi

2
Değişken sayılarına atamadan dizinin her benzersiz öğesinin oluşum sayısına erişmek istersem ne olur? Bununla ilgili ipuçları var mı?
sajis997

@ Sajis997 ile aynı hedefe sahibim. Ben bir grupta 'saymak' bir toplama işlevi olarak kullanmak istiyorum
p_sutherland

1
Çok büyük bir dizi (~ 30Gb) için her iki yöntemi kullanarak denedi. Numpy yönteminin hafızası bitti, ancak collections.Countergayet iyi çalıştı
Ivan Novikov

252

Kullanmaya ne dersiniz numpy.count_nonzero,

>>> 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
Bu cevap en çok oy alan cevaptan daha iyi görünüyor.
Alex

1
Bunun numpy.ndarrayOP'nin ilk istediği gibi çalışacağını düşünmüyorum .
LYu

5
@LYu - y bu cevapta bir np.ndarray. Ayrıca - çoğu olmasa bile np.something fonksiyonları ndarrays sorunsuz çalışır.
mmagnuski

132

Şahsen ben gitmek istiyorum: (y == 0).sum()ve(y == 1).sum()

Örneğin

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
Kesinlikle en kolay okunan şey. Soru en hızlı ve en az yer kaplayan sorudur
Nathan

Vektörü değerlendirdiği için numpy.count_nonzero'dan (y == 0) daha az yer tasarrufu sağlayabilir (y == 0)
Sridhar Thiagarajan

Bunu beğendim çünkü matlab / sum( vector==value )
oktave

39

Durumunuz için numpy.bincount'a da bakabilirsiniz.

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

Bu kod, denediğim daha büyük diziler için en hızlı çözümlerden biri olabilir. Sonucu bir liste olarak almak da bir bonus. Thanx!
Youngsup Kim

Eğer 'a' n boyutlu bir diziyse, şunu kullanabiliriz: np.bincount (np.reshape (a, a.size))
Ari

21

Dizinizi dönüştürme ylistesine lyapmak ve sonra l.count(1)vel.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])

Bunların sadece 0ve 1:

np.sum(y)

size bunların sayısını verir. np.sum(1-y)sıfırları verir.

Hafif genellik için, saymak istemiyorsanız 0ve sıfır değil (ancak muhtemelen 2 veya 3):

np.count_nonzero(y)

sıfır olmayanların sayısını verir.

Ancak daha karmaşık bir şeye ihtiyacınız varsa, numpy'nin güzel bir countseçenek sağlayacağını sanmıyorum . Bu durumda, koleksiyonlara gidin:

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

Bu bir dict gibi davranıyor

collections.Counter(y)[0]
> 8

13

Tam olarak hangi numarayı aradığınızı biliyorsanız aşağıdakileri kullanabilirsiniz;

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

dizinizde kaç kez 2 oluştuğunu döndürür.


8

Dürüst olmak gerekirse ben bir panda Serisi veya DataFrame dönüştürmek en kolay bulabilirsiniz:

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

Ya da Robert Muil tarafından önerilen bu güzel tek astar:

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

4
Sadece bir not: DataFrame veya numpy'ye gerek yok, doğrudan bir listeden bir Seriye gidebilir: pd.Series([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1]).value_counts()
Robert Muil

Harika, bu güzel bir tek katlı. Büyük Yukarı
wordsforthewise

8

Kimse kullanmayı numpy.bincount(input, minlength)önermedi minlength = np.size(input), ancak iyi bir çözüm gibi görünüyor ve kesinlikle en hızlı :

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

Bu numpy.unique(x, return_counts=True)ve ile arasındaki çılgın bir hızlanma numpy.bincount(x, minlength=np.max(x))!


histogramla nasıl karşılaştırılır?
john ktejik

@johnktejik np.histogramaynı şeyi hesaplamaz. histogramÜzgünüm, önerdiğim üç yaklaşımı karşılaştırmanın anlamı yok .
Næreen

1
@ Næreen bincountyalnızca tamsayılar için çalışır, bu nedenle OP'nin sorunu için çalışır, ancak başlıkta açıklanan genel sorun için olmayabilir. Ayrıca bincountçok büyük içleri olan dizilerle kullanmayı denediniz mi?
Kusursuz Gece

@ImperishableGece hayır Büyük ints ile denemedim, ama herkes bunu yapabilir ve kendi kriterlerini
yayınlayabilir

Bu takdir edilmemiş numara için teşekkürler! Makinemde bincountyaklaşık dört kat daha hızlı unique.
Björn Lindqvist

6

Ne hakkında len(y[y==0])ve len(y[y==1])?


6

y.tolist().count(val)

val 0 veya 1 ile

Bir python listesinin yerel bir işlevi olduğundan count, bu işlevi kullanmadan önce listeye dönüştürmek basit bir çözümdür.


5

Yine başka bir basit çözüm numpy.count_nonzero () kullanmak olabilir :

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

Adın sizi yanıltmasına izin vermeyin, tıpkı örnekte olduğu gibi boole ile birlikte kullanırsanız, hile yapar.


5

Olay sayısını saymak için şunları kullanabilirsiniz 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

Np.where kullanacaktım:

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

3

bir Seri tarafından sunulan yöntemlerden yararlanın:

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

Genel ve basit bir cevap:

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

bu da tam kod olarak sonuçlanır.

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

Şimdi MyArray birden çok boyuttaysa ve satırdaki değerlerin dağılımının varlığını saymak istiyorsanız (= bundan sonra desen)

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

Düzgün bir satırlık oluşturmak için sözlük anlama özelliğini kullanabilirsiniz. Sözlük anlama hakkında daha fazla bilgiyi burada bulabilirsiniz

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

Bu, ndarray'ınızdaki değerleri anahtar olarak ve sözlüklerin değerlerini sırasıyla anahtarların değerleri olarak içeren bir sözlük oluşturur.

Bu, bu biçimdeki dizilerde bir değerin oluşumlarını saymak istediğinizde işe yarayacaktır.


2

Bunu dene:

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

1

Bu, aşağıdaki yöntemle kolayca yapılabilir

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

1

Ndarray'ınız yalnızca 0 ve 1 içerdiğinden, 1s oluşumunu elde etmek için sum () ve 0'ların oluşumunu elde etmek için len () - sum () öğesini kullanabilirsiniz.

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

1

Burada sadece 1 ve 0 olan özel bir diziniz var. Yani bir hile kullanmak

np.mean(x)

dizinizdeki 1'lerin yüzdesini verir. Alternatif olarak,

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

dizinizde mutlak 1 ve 0 sayısını verecektir.


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

Seppo Enarvi'nin burada uygun bir cevap olmayı hak eden yorumu kopyalandı.


0

Bir adım daha içerir, ancak 2d diziler ve daha karmaşık filtreler için de çalışacak daha esnek bir çözüm, bir boole maskesi oluşturmak ve daha sonra maskede .sum () kullanmaktır.

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

0

Numpy veya koleksiyon modülü kullanmak istemiyorsanız bir sözlük kullanabilirsiniz:

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

sonuç:

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

Tabii ki bir if / else deyimini de kullanabilirsiniz. Counter fonksiyonunun hemen hemen aynı şeyi yaptığını düşünüyorum ama bu daha şeffaf.


0

Genel girişler için:

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

Bir sayı çıkarır:

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

Ve endeksler:

{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

Burada, belirli bir sayının oluşum sayısını sayabileceğiniz bir şey var: kodunuza göre

count_of_zero = listesi (y [y == 0]). sayısı (0)

Baskı (count_of_zero)

// eşleşmeye göre boolean değerleri olacak ve True değerine göre 0 sayısı döndürülecek


0

En hızlı yürütme ile ilgileniyorsanız, hangi değer (değerleri) arayacağınızı önceden bilirsiniz ve diziniz 1D'dir, aksi takdirde düzleştirilmiş dizideki sonuçla ilgilenirsiniz (bu durumda işlevin girişi gerekir olmak np.flatten(arr)yerine sadece daha arrsonra Numba arkadaşınız):

import numba as nb


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

veya paralelleştirmenin faydalı olabileceği çok büyük diziler için:

@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

Bunları np.count_nonzero()(kaçınılabilecek geçici bir dizi oluşturma sorunu da vardır) ve np.unique()tabanlı çözüme göre karşılaştırma

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 

ile oluşturulan girdi için:

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

Aşağıdaki grafikler elde edilir (grafiklerin ikinci sırası, daha hızlı yaklaşıma bir zumdur):

bm_full bm_zoom

Numba bazlı çözümün NumPy muadillerinden belirgin şekilde daha hızlı olduğunu ve çok büyük girdiler için paralel yaklaşım naif olandan daha hızlı olduğunu gösterir.


Tam kodu burada bulabilirsiniz .


0

Eğer jeneratörleri kullanarak çok büyük dizilerle uğraşıyorsanız bir seçenek olabilir. Buradaki güzel şey, bu yaklaşımın hem diziler hem de listeler için iyi çalışması ve herhangi bir ek pakete ihtiyacınız olmamasıdır. Ayrıca, bu kadar bellek kullanmıyorsunuz.

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'nin bunun için bir modülü var. Sadece küçük bir hack. Giriş dizinizi bölme olarak yerleştirin.

numpy.histogram(y, bins=y)

Çıktı 2 dizidir. Biri değerlerin kendisiyle, diğeri karşılık gelen frekanslarla.


'kutuların' bir sayı olması gerekmez mi?
john ktejik

1
Evet @johnktejik haklısın. Bu cevap vermez değil çalışır.
Næreen

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.