Як підрахувати появу певного елемента в ndarray в Python?


376

У Python у мене є ndarray, y який друкується якarray([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])

Я намагаюся порахувати, скільки 0s і скільки 1s є в цьому масиві.

Але коли я набираю y.count(0)або y.count(1), це говорить

numpy.ndarray об’єкт не має атрибута count

Що я повинен зробити?


8
Ви не можете використовувати функцію суми та довжини, оскільки у вас є лише тузи та нулі?
кодування ентузіаста

У цьому випадку також можна просто використовувати numpy.count_nonzero.
Монг Х. Нг

Відповіді:


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}

Нечистий спосіб :

Використання 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
Це було б `` унікально, counts = numpy.unique (a, return_counts = True) dict (zip (унікальний, рахується)) ``
подрібнення

25
Якщо ви хочете словник,dict(zip(*numpy.unique(a, return_counts=True)))
Seppo Enarvi

2
Що робити, якщо я хочу отримати доступ до кількості виникнення кожного унікального елемента масиву, не призначаючи змінну - підраховується. Якісь натяки на це?
sajis997

Я маю ту саму мету, що і @ sajis997. Я хочу використовувати "count" як функцію
згуртування в групі

1
Пробували з використанням обох методів для дуже великого масиву (~ 30Gb). У методу окуньки не вистачало пам’яті, тоді як collections.Counterпрацював просто чудово
Іван Новіков

252

Що з використанням 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
Ця відповідь здається кращою, ніж відповідь з найбільшою кількістю результатів.
Олексій

1
Я не думаю, що це спрацювало б так, numpy.ndarrayяк спочатку просили ОП.
ЛЮ

5
@LYu - y - відповідна np.ndarray у цій відповіді. Крім того - більшість, якщо не всі np.something функції працюють на ndarrays без проблем.
mmagnuski

132

Особисто я б пішов на: (y == 0).sum()і(y == 1).sum()

Напр

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
Це, безумовно, найпростіше читати. Питання в тому, який найшвидший та найефективніший у космосі
Натан

Mightbe менш ефективний простір, ніж numpy.count_nonzero (y == 0), оскільки він оцінює вектор (y == 0)
Шрідхар Тіагараджан

Мені це подобається, тому що схожий на sum( vector==value )
matlab

39

Для вашого випадку ви також можете заглянути в 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

Цей код може бути одним з найшвидших рішень для великих масивів, які я експериментував. Отримання результату у списку також є бонусом. Дякую!
Янгс Кім

І якщо "a" - це n-мірний масив, ми можемо просто використовувати: np.bincount (np.reshape (a, a.size))
Арі

21

Перетворіть свій масив yу список, lа потім зробіть l.count(1)іl.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])

Якщо ви знаєте, що вони просто 0і 1:

np.sum(y)

дає вам кількість одиниць. np.sum(1-y)дає нулі.

Для невеликої загальності, якщо ви хочете рахувати, 0а не нуль (але можливо 2 або 3):

np.count_nonzero(y)

дає кількість ненульових.

Але якщо вам потрібно щось складніше, я не думаю, що нуд надасть хороший countваріант. У такому випадку перейдіть до колекцій:

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

Це поводиться як диктант

collections.Counter(y)[0]
> 8

13

Якщо ви точно знаєте, яке число шукаєте, можете скористатися наступним;

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

повертає, скільки разів у вашому масиві відбулося 2.


8

Чесно кажучи, мені найпростіше перетворитись на серії панд або 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()

Або цей приємний одноколісний лайнер, запропонований Робертом Мейлом:

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

4
Лише зауваження: не потрібні DataFrame або numpy, можна перейти безпосередньо зі списку до серії: pd.Series([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1]).value_counts()
Роберт Мьюїл

Дивовижний, це приємний однолінійний. Великий вгору
словазразу

8

Ніхто не запропонував використовувати numpy.bincount(input, minlength)з minlength = np.size(input), але це , здається, гарне рішення, і , безумовно, самий швидкий :

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

Це божевільна швидкість між numpy.unique(x, return_counts=True)і numpy.bincount(x, minlength=np.max(x))!


як це порівняти з гістограмою?
Джон Ктейджик

@johnktejik np.histogramне обчислює те саме. Немає сенсу порівнювати три запропоновані мною підходи з histogramфункцією, вибачте.
Næreen

1
@ Næreen bincountпрацює лише для цілих чисел, тому він працює для проблеми ОП, але, можливо, не для загальної проблеми, описаної в заголовку. Ви також намагалися використовувати bincountмасиви з дуже великими входами?
Непрохідна ніч

@ImperishableNight ні, я не пробував з великими ints, але будь-хто бажає це зробити і розмістити свій власний орієнтир :-)
Næreen

Дякую за цей недооцінений трюк! На моїй машині bincountце приблизно в чотири рази швидше, ніж unique.
Бьорн Ліндквіст


6

y.tolist().count(val)

з val 0 або 1

Оскільки у списку python є нативна функція count, перетворення до списку перед використанням цієї функції є простим рішенням.


5

Ще одним простим рішенням може бути використання 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

Не дозволяйте ім'я вводити вас в оману, якщо ви використовуєте його з булевим так само, як у прикладі, це зробить трюк.


5

Для підрахунку кількості подій можна скористатися 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:

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

3

скористайтеся методами, пропонованими серією:

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

Загальна і проста відповідь буде:

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

що призведе до отримання цього повного коду як прикладу

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

Тепер, якщо MyArray знаходиться в декількох вимірах, і ви хочете порахувати виникнення розподілу значень у рядку (= шаблон далі)

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

Ви можете використовувати розуміння словника, щоб створити акуратний однокласник. Більше про розуміння словника можна прочитати тут

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

Це створить словник зі значеннями у вашому ndarray як ключами, а відліки значень як значення для клавіш відповідно.

Це буде працювати, коли ви хочете порахувати виникнення значення у масивах цього формату.


2

Спробуйте це:

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

1

Це легко зробити за допомогою наступного методу

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

1

Оскільки ваш ndarray містить лише 0 і 1, ви можете використовувати sum (), щоб отримати виникнення 1s, а len () - sum (), щоб отримати вхід 0.

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

1

У вас є спеціальний масив із лише 1 та 0 тут. Тож хитрість - використовувати

np.mean(x)

що дає вам відсоток 1 у вашому масиві. Як варіант, використовувати

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

дасть вам абсолютне число 1 і 0 у вашому масиві.


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

Щойно скопійований тут коментар Seppo Enarvi, який заслуговує на правильну відповідь


0

Він передбачає ще один крок, але більш гнучким рішенням, яке також працювало б для 2d-масивів і складніших фільтрів, є створення булевої маски, а потім використання .sum () на масці.

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

0

Якщо ви не хочете використовувати numpy або модуль колекції, ви можете скористатися словником:

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

результат:

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

Звичайно, ви також можете використовувати оператор if / else. Я думаю, що функція Counter робить майже те саме, але це більш прозоро.


0

Для загальних записів:

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

Виведе підрахунок:

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

І індекси:

{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

тут у мене є щось, через що ви можете порахувати кількість зустрічань певного числа: відповідно до вашого коду

count_of_zero = список (y [y == 0]). count (0)

друк (count_of_zero)

// відповідно до відповідності буде булеві значення, а відповідно до значення True повернеться число 0


0

Якщо ви зацікавлені в якнайшвидшому виконанні, ви заздалегідь знаєте, яке значення (-и) шукати, і ваш масив - 1D, або вас іншим чином цікавить результат на сплющеному масиві (у такому випадку вхід функції повинен бути, np.flatten(arr)а не просто arr), тоді Numba - ваш друг:

import numba as nb


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

або, для дуже великих масивів, де паралелізація може бути корисною:

@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

Бенчмаркінг цих проти np.count_nonzero()(що також має проблему створення тимчасового масиву, якого можна уникнути) та np.unique()рішення на базі

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 

для введення, генерованого за допомогою:

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

отримуються наступні сюжети (другий ряд сюжетів - це масштабування при більш швидкому підході):

bm_full bm_zoom

Показано, що рішення на основі Numba помітно швидше, ніж аналоги NumPy, і для дуже великих входів паралельний підхід швидший, ніж наївний.


Повний код доступний тут .


0

якщо ви маєте справу з дуже великими масивами за допомогою генераторів, це може бути варіантом. Приємно, що цей підхід працює добре як для масивів, так і для списків, і вам не потрібен додатковий пакет. Крім того, ви не використовуєте стільки пам’яті.

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 має модуль для цього. Просто невеликий хак. Помістіть вхідний масив як бін.

numpy.histogram(y, bins=y)

Вихід - 2 масиви. Один із самими значеннями, інший із відповідними частотами.


чи не слід вважати, що "бункери" мають бути?
Джон Ктейджик

1
Так @johnktejik ви праві. Ця відповідь не працює.
Næreen

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.