วิธีการนับการเกิดขึ้นของรายการบางอย่างใน ndarray ใน Python?


376

ใน Python ฉันมีคำสั่ง y ที่พิมพ์เป็นarray([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])

ฉันพยายามนับจำนวน 0และมีกี่ตัว1ในอาร์เรย์นี้

แต่เมื่อฉันพิมพ์y.count(0)หรือy.count(1)มันพูดว่า

numpy.ndarray วัตถุไม่มีแอตทริบิวต์ count

ฉันควรทำอย่างไรดี?


8
คุณไม่สามารถใช้ฟังก์ชันผลรวมและความยาวได้เนื่องจากคุณมีเอซและเลขศูนย์เท่านั้น
codingEnthusiast

numpy.count_nonzeroในกรณีนี้ก็ยังเป็นไปได้ที่จะใช้เพียงแค่
Mong H. Ng

คำตอบ:


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
นั่นจะเป็น `` `ไม่ซ้ำกันนับ = numpy.unique (a, return_counts = True) dict (zip (ไม่ซ้ำกันนับ))` ``
ทำลาย

25
หากคุณต้องการพจนานุกรมdict(zip(*numpy.unique(a, return_counts=True)))
Seppo Enarvi

2
จะเกิดอะไรขึ้นถ้าฉันต้องการเข้าถึงจำนวนครั้งขององค์ประกอบที่ไม่ซ้ำกันของอาร์เรย์โดยไม่ต้องกำหนดให้กับตัวแปร - นับ มีคำแนะนำอะไรบ้าง?
sajis997

ฉันมีเป้าหมายเดียวกับ @ sajis997 ฉันต้องการใช้ 'count' เป็นฟังก์ชันการรวมใน groupby
p_sutherland

1
พยายามใช้ทั้งสองวิธีสำหรับอาร์เรย์ที่มีขนาดใหญ่มาก (~ 30Gb) วิธี Numpy มีหน่วยความจำไม่เพียงพอในขณะที่collections.Counterทำงานได้ดี
Ivan Novikov

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
คำตอบนี้ดูเหมือนจะดีกว่าคำตอบที่มี upvotes มากที่สุด
อเล็กซ์

1
ฉันไม่คิดว่ามันจะใช้งานได้numpy.ndarrayเหมือนที่ OP เคยถาม
LYu

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
มันง่ายที่สุดในการอ่าน คำถามคือสิ่งที่เร็วที่สุดและพื้นที่มีประสิทธิภาพมากที่สุด
นาธาน

อาจมีพื้นที่น้อยกว่าที่มีประสิทธิภาพกว่า numpy.count_nonzero (y == 0) เนื่องจากมันประเมินเวกเตอร์ (y == 0)
Sridhar Thiagarajan

ฉันชอบสิ่งนี้เพราะคล้ายกับ 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

รหัสนี้อาจเป็นวิธีแก้ปัญหาที่เร็วที่สุดสำหรับอาร์เรย์ขนาดใหญ่ที่ฉันทำการทดลอง การได้รับผลลัพธ์ในรายการก็เป็นโบนัสเช่นกัน Thanx!
Youngsup Kim

และถ้า 'a' เป็นอาร์เรย์ n มิติเราสามารถใช้: np.bincount (np.reshape (a, a.size))
Ari

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

สิ่งนี้ทำตัวเหมือน dict

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

หรือเป็นหนึ่งในสายการบินที่แนะนำโดย Robert Muil:

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

เจ๋งมากนั่นเป็นหนึ่งซับที่ดี โตขึ้น
คำต่อไป

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


เปรียบเทียบกับฮิสโตแกรมได้อย่างไร?
john ktejik

@johnktejik np.histogramไม่ได้คำนวณสิ่งเดียวกัน ไม่มีจุดเปรียบเทียบสามแนวทางที่ฉันเสนอกับhistogramฟังก์ชันขออภัย
Næreen

1
@ Næreen bincountใช้งานได้กับจำนวนเต็มเท่านั้นดังนั้นจึงใช้งานได้กับปัญหาของ OP แต่อาจไม่ใช่ปัญหาทั่วไปที่อธิบายไว้ในชื่อ คุณลองใช้bincountกับอาร์เรย์ที่มี ints ใหญ่มากหรือไม่?
คืน

@ImperishableNight ไม่ฉันไม่ได้ลองกับ ints ขนาดใหญ่ แต่ทุกคนยินดีที่จะทำเช่นนั้นและโพสต์มาตรฐานของตัวเอง :-)
Næreen

ขอบคุณสำหรับเคล็ดลับที่ประเมินค่าต่ำกว่านี้! ในเครื่องของฉันเป็นเรื่องเกี่ยวกับสี่ครั้งเร็วกว่าbincount unique
Björn Lindqvist


6

y.tolist().count(val)

ด้วย val 0 หรือ 1

เนื่องจากรายการไพ ธ อนมีฟังก์ชั่นพื้นฐาน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


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 ของคุณเป็นคีย์และจำนวนของค่าเป็นค่าสำหรับคีย์ตามลำดับ

สิ่งนี้จะทำงานเมื่อใดก็ตามที่คุณต้องการนับจำนวนค่าในอาร์เรย์ของรูปแบบนี้



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 () เพื่อรับการเกิดขึ้นของ 0s

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

1

คุณมีอาร์เรย์พิเศษที่มีเพียง 1 และ 0 ที่นี่ ดังนั้นเคล็ดลับคือการใช้

np.mean(x)

ซึ่งให้เปอร์เซ็นต์ของ 1s ในอาร์เรย์ของคุณ หรือใช้

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

จะให้จำนวนที่แน่นอน 1 และ 0 ในอาร์เรย์ของคุณ


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

เพิ่งคัดลอกความคิดเห็นของ Seppo Enarvi ที่นี่ซึ่งสมควรได้รับคำตอบที่เหมาะสม


0

มันเกี่ยวข้องกับอีกขั้นตอนหนึ่ง แต่วิธีแก้ปัญหาที่ยืดหยุ่นกว่าซึ่งจะใช้กับอาร์เรย์ 2d และตัวกรองที่ซับซ้อนมากขึ้นคือการสร้างมาสก์บูลีนแล้วใช้. suum () บนมาสก์

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

0

หากคุณไม่ต้องการใช้โมดูลหรือคอลเล็กชันคุณสามารถใช้พจนานุกรม:

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 ฉันคิดว่าฟังก์ชั่นตัวนับเกือบจะเหมือนกัน แต่มันก็โปร่งใสกว่า


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]). นับ (0)

พิมพ์ (count_of_zero)

// ตามการจับคู่จะมีค่าบูลีนและตามค่าจริงหมายเลข 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 อย่างเห็นได้ชัดและสำหรับอินพุตที่มีขนาดใหญ่มากวิธีการแบบขนานนั้นเร็วกว่าแบบไร้เดียงสา


รหัสเต็มมีที่นี่


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 อาร์เรย์ หนึ่งที่มีค่าตัวเองอื่น ๆ ที่มีความถี่ที่สอดคล้องกัน


ไม่ 'ถังขยะ' ควรจะเป็นตัวเลขหรือไม่?
john ktejik

1
ใช่ @johnktejik คุณพูดถูก คำตอบนี้จะไม่ทำงาน
Næreen

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.