Как посчитать вхождение определенного элемента в ndarray в Python?

376

В Python у меня есть ndarray, y который печатается какarray([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])

Я пытаюсь подсчитать, сколько 0и сколько 1s в этом массиве.

Но когда я печатаю y.count(0)или y.count(1), это говорит

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

Что мне делать?

mflowww
источник
8
Вы не можете использовать функцию суммы и длины, так как у вас есть только тузы и нули?
codingEnthusiast
В этом случае также можно просто использовать 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})
Ozgur
источник
3
Это было бы `` `уникально, countts = numpy.unique (a, return_counts = True) dict (zip (уникально, рассчитывает))` ``
уничтожение
25
Если вы хотите словарь,dict(zip(*numpy.unique(a, return_counts=True)))
Сеппо Энарви
2
Что делать, если я хочу получить доступ к числу экземпляров каждого уникального элемента массива без присваивания переменной - рассчитывает. Есть намеки на это?
sajis997
У меня та же цель, что и у @ sajis997. Я хочу использовать 'count' в качестве функции агрегирования в groupby
p_sutherland
1
Пробовал использовать оба метода для очень большого массива (~ 30Gb). Метод Numpy исчерпал память, тогда как 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как первоначально просили OP.
LYu
5
@LYu - y является np.ndarray в этом ответе. Кроме того - большинство, если не все функции np.something работают на ndarrays без проблем.
Магнуски
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
Это определенно легче всего читать. Вопрос в том, какой из них быстрее и эффективнее всего
Натан
Может быть меньше места, чем numpy.count_nonzero (y == 0), так как он оценивает вектор (y == 0)
Шридхар Тиагараджан
Мне это нравится, потому что похоже на matlab / octavesum( vector==value )
ePi272314
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
Akavall
источник
Этот код может быть одним из самых быстрых решений для больших массивов, которые я экспериментировал. Получение результата в виде списка также является бонусом. Thanx!
Янгсуп Ким
И если '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)

дает число ненулевое.

Но если вам нужно что-то более сложное, я не думаю, что numpy предоставит хороший countвариант. В этом случае перейдите в коллекции:

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

Это ведет себя как диктат

collections.Counter(y)[0]
> 8
Joel
источник
13

Если вы точно знаете, какой номер вы ищете, вы можете использовать следующее;

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

возвращает, сколько раз 2 произошло в вашем массиве.

CanCeylan
источник
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()
wordsforthewise
источник
4
Просто примечание: не нужен DataFrame или NumPy, можно перейти непосредственно из списка в серии: pd.Series([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1]).value_counts()
Роберт
Круто, это хорошо, один вкладыш. Big up
слова для этого
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))!

Næreen
источник
как это по сравнению с гистограммой?
Джон Ктехик
@johnktejik np.histogramне вычисляет то же самое. Нет смысла сравнивать три подхода, которые я предлагаю, с histogramфункцией, извините.
Næreen
1
@ Næreen bincountработает только для целых чисел, поэтому он работает для задачи ОП, но, возможно, не для общей проблемы, описанной в заголовке. Также вы пытались использовать bincountс массивами с очень большими целыми числами?
Нетленная ночь
@ImperishableNight Нет, я не пробовал с большими целыми, но любой желающий может сделать это и опубликовать свой собственный тест :-)
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

Не позволяйте имени вводить вас в заблуждение, если вы используете его с логическим значением, как в примере, это поможет вам.

Nazo
источник
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
kmario23
источник
4

Я бы использовал np.where:

how_many_0 = len(np.where(a==0.)[0])
how_many_1 = len(np.where(a==1.)[0])
MAXg
источник
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 в качестве ключей и подсчетом значений в качестве значений для ключей соответственно.

Это будет работать всякий раз, когда вы хотите посчитать вхождения значения в массивах этого формата.

CB Madsen
источник
2

Попробуй это:

a = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])
list(a).count(1)
jarh1992
источник
1

Это можно легко сделать следующим способом

y = np.array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])
y.tolist().count(1)
user7055304
источник
1

Поскольку ваш ndarray содержит только 0 и 1, вы можете использовать sum () для получения вхождения 1s и len () - sum () для получения вхождения 0s.

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 в вашем массиве.

CathyQian
источник
1
dict(zip(*numpy.unique(y, return_counts=True)))

Просто скопировал здесь комментарий Сеппо Энарви, который заслуживает правильного ответа.

Dr_Hope
источник
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 делает почти то же самое, но это более прозрачно.

JLT
источник
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 = лист (у [у == 0]). кол (0)

печать (count_of_zero)

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

Парень
источник
0

Если вас интересует самое быстрое выполнение, вы заранее знаете, какое значение (а) нужно искать, и ваш массив является 1D, или вы иным образом интересуетесь результатом для уплощенного массива (в этом случае ввод функции должен будь np.flatten(arr)скорее чем просто arr) тогда Нумба твой друг

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, и для очень больших входов параллельный подход быстрее, чем наивный.


Полный код доступен здесь .

norok2
источник
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
-1
using numpy.count

$ a = [0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1]

$ np.count(a, 1)
Ангги Пермана Харианья
источник
Что здесь со знаками доллара?
Трипли