统计矩阵中小于某个值的所有数值数量

91

我需要计算一个矩阵(2维数组)中所有小于200的值的数量。

我编写了以下代码:

za=0   
p31 = numpy.asarray(o31)   
for i in range(o31.size[0]):   
    for j in range(o32.size[1]):   
        if p31[i,j]<200:   
            za=za+1   
print za

o31 是一张图片,我将其转换为矩阵,然后找到了其中的值。

有没有更简单的方法来做这件事?


1
这只是打印小于200的值的数量,而不是实际的值吗? - Burhan Khalid
是的,我只需要所有值的总和而不是实际的值本身。 - gran_profaci
1
这里也没有得到总和。将za设置为空列表za = [],然后za.append(p31[i,j]),最后在for循环之外,print sum(za);但是我相信有更好的方法,因为你正在使用numpy。 - Burhan Khalid
6个回答

129

使用布尔数组非常简单:

p31 = numpy.asarray(o31)
za = (p31 < 200).sum() # p31<200 is a boolean array, so `sum` counts the number of True elements

4
我认为这应该是最佳答案。np.where 显然也可行,但它提供了额外的信息,在此不需要,并使答案变得略微复杂,性能也稍慢。 - Iddo weiner

110

numpy.where函数是您的好朋友。由于它是实现在完全利用数组数据类型的基础上,对于大型图像,您应该会注意到比您提供的纯Python解决方案更快速的改进。

直接使用 numpy.where 将产生一个布尔掩码,指示某些值是否与您的条件匹配:

>>> data
array([[1, 8],
       [3, 4]])
>>> numpy.where( data > 3 )
(array([0, 1]), array([1, 1]))

并且该掩码可以直接用于索引数组以获取实际值:

>>> data[ numpy.where( data > 3 ) ]
array([8, 4])

接下来你需要从哪里获取数据,取决于你希望结果以何种形式呈现。


13
谢谢...但我需要的是数值总数,而不是数值本身...我应该执行sum(numpy.where(data<200))? - gran_profaci
9
如果你想要值的数量而不是总和,可以使用len(numpy.where(data<200))。 - jimh
1
如果将条件更改为> 0,则会返回(array([0,0,1,1]),array([0,1,0,1]))。这是什么意思?还是一个错误吗? - hihell
1
这个方法过于复杂。@neonneo的方法更加简单明了,而且更好地回答了问题。 - waterproof
@jimh 对我来说,np.where返回一个元组,必须执行len(np.where(...)[0])。 - user1114

32

有很多方法可以实现这一点,比如flatten-and-filter或简单地使用枚举,但我认为使用布尔/mask数组是最容易的方法(并且如果我没记错的话速度更快):

>>> y = np.array([[123,24123,32432], [234,24,23]])
array([[  123, 24123, 32432],
       [  234,    24,    23]])
>>> b = y > 200
>>> b
array([[False,  True,  True],
       [ True, False, False]], dtype=bool)
>>> y[b]
array([24123, 32432,   234])
>>> len(y[b])
3
>>>> y[b].sum()
56789

更新:

如nneonneo所回答的,如果您只想知道通过阈值的元素数量,您可以简单地执行以下操作:

>>>> (y>200).sum()
3

这是一个更简单的解决方案。


filter的速度比较:

### use boolean/mask array ###

b = y > 200

%timeit y[b]
100000 loops, best of 3: 3.31 us per loop

%timeit y[y>200]
100000 loops, best of 3: 7.57 us per loop

### use filter ###

x = y.ravel()
%timeit filter(lambda x:x>200, x)
100000 loops, best of 3: 9.33 us per loop

%timeit np.array(filter(lambda x:x>200, x))
10000 loops, best of 3: 21.7 us per loop

%timeit filter(lambda x:x>200, y.ravel())
100000 loops, best of 3: 11.2 us per loop

%timeit np.array(filter(lambda x:x>200, y.ravel()))
10000 loops, best of 3: 22.9 us per loop

*** use numpy.where ***

nb = np.where(y>200)
%timeit y[nb]
100000 loops, best of 3: 2.42 us per loop

%timeit y[np.where(y>200)]
100000 loops, best of 3: 10.3 us per loop

2
timeit y[b] 从 filter 中计算的一半代码中省略了。%timeit y[y>200] 是等价的。 - Mad Physicist

10

这是一种使用花式索引并将实际值作为中间步骤的变体:

p31 = numpy.asarray(o31)
values = p31[p31<200]
za = len(values)

这只是普通的布尔索引。 - Mad Physicist

6

要在 numpy 数组中计算大于 x 的值的数量,可以使用以下代码:

n = len(matrix[matrix > x])

布尔索引返回一个数组,其中只包含满足条件(矩阵 > x)的元素。然后使用len()函数计算这些值的数量。

1
你可能需要解释为什么这个代码能够工作。我猜是因为重载了 __gt__,但这并不明显。 - Adrian W

1
你可以使用numpy.count_nonzero,将整个内容转换为一行代码:
za = numpy.count_nonzero(numpy.asarray(o31)<200)  #as written in the code

你可以使用 np.count_nonzero(np.less_than(o3, 200)) 来避免显式调用 asarray - Mad Physicist

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接