如何计算Python中ndarray中某些项目的出现?


376

在Python中,我有一个ndarray y 打印为array([0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1])

我试图计算这个数组中有多少个0和多少个1

但是当我输入y.count(0)or时y.count(1),它说

numpy.ndarray 对象没有属性 count

我该怎么办?


8
因为只有A和零,所以不能使用sum和length函数吗?
–codingEnthusiast

在这种情况下,也可以简单地使用numpy.count_nonzero
Mong H. Ng

Answers:


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

使用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(unique,counts))”
粉碎

25
如果您想要字典,dict(zip(*numpy.unique(a, return_counts=True)))
Seppo Enarvi

2
如果我想访问数组中每个唯一元素的出现次数而不分配变量,该怎么办?有什么暗示吗?
sajis997

我的目标与@ sajis997相同。我想在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
这个答案似乎比投票最多的答案更好。
亚历克斯(Alex)

1
我认为这不会numpy.ndarray像OP最初要求的那样有效。
LYu

5
@LYu-y是此答案中的np.ndarray。另外-大多数(如果不是全部)np.something函数可以在ndarrays上正常工作。
mmagnuski '18

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
这绝对是最容易阅读的。问题是哪一个最快,最节省空间?
Nathan

可能比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

对于我尝试过的较大阵列,此代码可能是最快的解决方案之一。将结果作为列表获得也是一种奖励。谢谢!
Youngsup Kim,

如果“一”是n维数组,我们可以只使用:np.bincount(np.reshape(一,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])

如果你知道,他们只是01

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

13

如果您确切知道要查找的号码,则可以使用以下代码;

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

返回数组中发生2的次数。


8

老实说,我发现将其转换为pandas系列或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

太棒了,这是一个不错的选择。大起来
wordsforthewise

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只适用于整数,因此它适用于OP的问题,但不适用于标题中所述的一般性问题。您是否也尝试过使用bincount具有很大整数的数组?
永恒之夜

@ImperishableNight不,我没有大整数试过,但欢迎任何人这样做,并发布自己的基准:-)
Næreen

谢谢你这个没被理解的把戏!在我的机器bincount上的速度比机器快四倍unique
比约恩·林德奎斯特(BjörnLindqvist)


6

y.tolist().count(val)

使用val 0或1

由于python列表具有本机函数count,因此在使用该函数之前将其转换为list是一个简单的解决方案。


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


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具有多个维度,并且您要计算行中值分布的出现次数(此后为pattern)

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()获得1的出现,并使用len()-sum()获得0的出现。

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数组和更复杂的过滤器也适用的更灵活的解决方案是创建一个布尔掩码,然后在掩码上使用.sum()。

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

0

如果您不想使用numpy或collections模块,则可以使用字典:

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 = list(y [y == 0])。count(0)

打印(count_of_zero)

//根据匹配项,将有布尔值,根据True值,将返回数字0


0

如果您对最快的执行感兴趣,那么您会事先知道要查找的值,并且您的数组是一维的,否则您对展平数组上的结果感兴趣(在这种情况下,函数的输入应是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,您是对的。这个答案并不能正常工作。
奈恩

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.