Làm thế nào để đếm sự xuất hiện của một số mục nhất định trong một ndarray trong Python?


376

Trong Python, tôi có một ndarray y được in làarray([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])

Tôi đang cố gắng đếm xem có bao nhiêu 0s và bao nhiêu 1s trong mảng này.

Nhưng khi tôi gõ y.count(0)hoặc y.count(1), nó nói

numpy.ndarray đối tượng không có thuộc tính count

Tôi nên làm gì?


8
Bạn không thể sử dụng hàm tổng và độ dài, vì bạn chỉ có số không và số không?
mã hóaEnthusiast

Trong trường hợp này, nó cũng có thể chỉ đơn giản là sử dụng numpy.count_nonzero.
Mong H. Ng

Câu trả lời:


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}

Cách không numpy :

Sử dụng 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
Đó sẽ là `` `unique, Counts = numpy.unique (a, return_counts = True) dict (zip (unique, Counts))` `
băm nhỏ

25
Nếu bạn muốn từ điển,dict(zip(*numpy.unique(a, return_counts=True)))
Seppo Enarvi

2
Điều gì xảy ra nếu tôi muốn truy cập số lần xuất hiện của từng thành phần duy nhất của mảng mà không gán cho biến - đếm. Bất kỳ gợi ý về điều đó?
sajis997

Tôi có cùng mục tiêu với @ sajis997. Tôi muốn sử dụng 'đếm' như một hàm tổng hợp trong một nhóm
p_sutherland 15/03/18

1
Đã thử sử dụng cả hai phương pháp cho một mảng rất lớn (~ 30Gb). Phương pháp Numpy hết bộ nhớ trong khi phương pháp collections.Counterhoạt động tốt
Ivan Novikov

252

Còn việc sử dụng numpy.count_nonzero, đại loại như

>>> 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
Câu trả lời này có vẻ tốt hơn câu trả lời nhiều nhất.
Alex

1
Tôi không nghĩ rằng điều này sẽ làm việc numpy.ndarraynhư OP ban đầu yêu cầu.
LYu

5
@LYu - y là một np.ndarray trong câu trả lời này. Ngoài ra - hầu hết nếu không phải tất cả các hàm np.s Something đều hoạt động trên ndarrays mà không gặp vấn đề gì.
mmagnuski

132

Cá nhân, tôi sẽ đi: (y == 0).sum()(y == 1).sum()

Ví dụ

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
Nó chắc chắn là dễ đọc nhất. Câu hỏi đặt ra là nhanh nhất và hiệu quả nhất về không gian
Nathan

Có thể ít không gian hiệu quả hơn numpy.count_nonzero (y == 0), vì nó đánh giá vectơ (y == 0)
Sridhar Thiagarajan

Tôi thích điều này vì tương tự như matlab / octavesum( vector==value )
ePi272314

39

Đối với trường hợp của bạn, bạn cũng có thể xem xét 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

Mã này có thể là một trong những giải pháp nhanh nhất cho các mảng lớn hơn mà tôi đã thử nghiệm. Lấy kết quả là một danh sách cũng là một phần thưởng. Thanx!
Youngsup Kim

Và nếu 'a' là mảng n chiều, chúng ta chỉ có thể sử dụng: np.bincount (np.reshape (a, a.size))
Ari

21

Chuyển đổi mảng của bạn ythành danh sách lvà sau đó làm 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])

Nếu bạn biết rằng họ chỉ 01:

np.sum(y)

cung cấp cho bạn số lượng những người. np.sum(1-y)cho số không.

Đối với tính tổng quát, nếu bạn muốn đếm 0và không bằng 0 (nhưng có thể là 2 hoặc 3):

np.count_nonzero(y)

đưa ra số lượng khác không.

Nhưng nếu bạn cần một cái gì đó phức tạp hơn, tôi không nghĩ numpy sẽ cung cấp một countlựa chọn tốt . Trong trường hợp đó, đi đến bộ sưu tập:

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

Điều này hành xử như một dict

collections.Counter(y)[0]
> 8

13

Nếu bạn biết chính xác số bạn đang tìm kiếm, bạn có thể sử dụng như sau;

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

trả về số lần 2 xảy ra trong mảng của bạn.


8

Thành thật mà nói tôi thấy dễ dàng nhất để chuyển đổi thành Sê-ri gấu trúc hoặc Khung dữ liệu:

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

Hoặc chiếc áo lót đẹp này được đề xuất bởi Robert Muil:

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

4
Chỉ cần một lưu ý: không cần DataFrame hoặc numpy, có thể chuyển trực tiếp từ danh sách sang Sê-ri: pd.Series([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1]).value_counts()
Robert Muil

Tuyệt vời, đó là một lót tốt đẹp. Lớn lên
lời giới thiệu

8

Không ai đề xuất sử dụng numpy.bincount(input, minlength)với minlength = np.size(input), nhưng nó có vẻ là một giải pháp tốt và chắc chắn là nhanh nhất :

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

Đó là một sự tăng tốc điên rồ giữa numpy.unique(x, return_counts=True)numpy.bincount(x, minlength=np.max(x))!


Hows nó so với biểu đồ?
john ktejik

@johnktejik np.histogramkhông tính toán điều tương tự. Không có điểm so sánh ba cách tiếp cận tôi đề xuất với histogramchức năng, xin lỗi.
Nreen

1
@ Næreen bincountchỉ hoạt động cho các số nguyên mặc dù vậy, nó hoạt động cho vấn đề của OP, nhưng có thể không hoạt động cho vấn đề chung được mô tả trong tiêu đề. Ngoài ra bạn đã thử sử dụng bincountvới mảng với ints rất lớn?
Đêm vô thường

@ImperishableNight no Tôi chưa từng thử với ints lớn, nhưng bất cứ ai cũng được chào đón để làm điều đó và đăng điểm chuẩn của riêng họ :-)
Nreen

Cảm ơn bạn cho thủ thuật đánh giá thấp này! Trên máy của tôi bincountnhanh hơn khoảng bốn lần unique.
Bjorn Lindqvist


6

y.tolist().count(val)

với giá trị 0 hoặc 1

Vì danh sách python có chức năng gốc count, chuyển đổi thành danh sách trước khi sử dụng chức năng đó là một giải pháp đơn giản.


5

Tuy nhiên, một giải pháp đơn giản khác có thể là sử dụng 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

Đừng để cái tên đánh lừa bạn, nếu bạn sử dụng nó với boolean giống như trong ví dụ, nó sẽ thực hiện thủ thuật.


5

Để đếm số lần xuất hiện, bạn có thể sử dụng 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

Tôi sẽ sử dụng np.where:

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

3

tận dụng các phương thức được cung cấp bởi Sê-ri:

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

Một câu trả lời chung chung và đơn giản sẽ là:

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

mà sẽ dẫn đến mã đầy đủ này là mẫu mực

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

Bây giờ nếu MyArray có nhiều chiều và bạn muốn tính sự xuất hiện của phân phối các giá trị trong dòng (= mẫu sau đây)

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

Bạn có thể sử dụng khả năng hiểu từ điển để tạo ra một lớp lót gọn gàng. Thông tin thêm về hiểu từ điển có thể được tìm thấy ở đây

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

Điều này sẽ tạo một từ điển với các giá trị trong ndarray của bạn dưới dạng các khóa và đếm các giá trị làm giá trị tương ứng cho các khóa.

Điều này sẽ hoạt động bất cứ khi nào bạn muốn đếm số lần xuất hiện của một giá trị trong mảng của định dạng này.


2

Thử cái này:

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

1

Điều này có thể được thực hiện dễ dàng trong phương pháp sau

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

1

Vì ndarray của bạn chỉ chứa 0 và 1, bạn có thể sử dụng sum () để có được sự xuất hiện của 1s và len () - sum () để có được sự xuất hiện của 0s.

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

1

Bạn có một mảng đặc biệt chỉ có 1 và 0 ở đây. Vì vậy, một mẹo là sử dụng

np.mean(x)

cung cấp cho bạn tỷ lệ phần trăm của 1 trong mảng của bạn. Cách khác, sử dụng

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

sẽ cung cấp cho bạn số tuyệt đối là 1 và 0 trong mảng của bạn.


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

Chỉ cần sao chép nhận xét của Seppo Enarvi ở đây xứng đáng là một câu trả lời thích hợp


0

Nó bao gồm một bước nữa, nhưng một giải pháp linh hoạt hơn cũng sẽ hoạt động cho mảng 2d và các bộ lọc phức tạp hơn là tạo mặt nạ boolean và sau đó sử dụng .sum () trên mặt nạ.

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

0

Nếu bạn không muốn sử dụng numpy hoặc mô-đun bộ sưu tập, bạn có thể sử dụng từ điển:

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

kết quả:

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

Tất nhiên bạn cũng có thể sử dụng một câu lệnh if / other. Tôi nghĩ rằng chức năng Counter thực hiện gần như tương tự nhưng điều này là trong suốt hơn.


0

Đối với các mục chung:

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

Sẽ xuất ra một số lượng:

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

Và các chỉ số:

{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

Ở đây tôi có một cái gì đó, thông qua đó bạn có thể đếm số lần xuất hiện của một số cụ thể: theo mã của bạn

đếm_of_zero = danh sách (y [y == 0]). đếm (0)

in (đếm_of_zero)

// theo trận đấu sẽ có các giá trị boolean và theo giá trị True, số 0 sẽ được trả về


0

Nếu bạn quan tâm đến việc thực hiện nhanh nhất, bạn sẽ biết trước (các) giá trị nào cần tìm và mảng của bạn là 1D hoặc nếu không bạn quan tâm đến kết quả trên mảng được làm phẳng (trong trường hợp đó là đầu vào của hàm nên được np.flatten(arr)chứ không phải chỉ arr), sau đó Numba là bạn của bạn:

import numba as nb


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

hoặc, đối với các mảng rất lớn, nơi song song hóa có thể có lợi:

@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

Điểm chuẩn những điểm này np.count_nonzero()(điều này cũng có vấn đề tạo ra một mảng tạm thời có thể tránh được) và np.unique()giải pháp dựa trên

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 

cho đầu vào được tạo bằng:

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

các ô sau đây thu được (hàng ô thứ hai là phóng to phương pháp tiếp cận nhanh hơn):

bm_full bm_zoom

Cho thấy giải pháp dựa trên Numba nhanh hơn đáng kể so với các đối tác NumPy và, đối với các đầu vào rất lớn, cách tiếp cận song song nhanh hơn so với phương pháp ngây thơ.


Mã đầy đủ có sẵn ở đây .


0

nếu bạn đang xử lý các mảng rất lớn bằng cách sử dụng các trình tạo có thể là một lựa chọn. Điều tuyệt vời ở đây là cách tiếp cận này hoạt động tốt cho cả mảng và danh sách và bạn không cần bất kỳ gói bổ sung nào. Ngoài ra, bạn không sử dụng nhiều bộ nhớ.

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 có một mô-đun cho việc này. Chỉ là một hack nhỏ. Đặt mảng đầu vào của bạn dưới dạng thùng.

numpy.histogram(y, bins=y)

Đầu ra là 2 mảng. Một với các giá trị chính nó, khác với các tần số tương ứng.


không phải là 'thùng' được cho là một số?
john ktejik

1
Có @johnktejik bạn đúng. Câu trả lời này không hoạt động.
Nreen

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.