在Python中找到numpy数组(或元组)中除零以外的最小/最大值

70

我有一个数组。有效值不为零(正数或负数)。我想在不考虑零的情况下找到数组中的最小值和最大值。例如,如果数字仅为负数,则零将会成为问题。


4
你有什么问题?你尝试过什么?它为什么不起作用? - hmakholm left over Monica
6个回答

119

这样怎么样:

import numpy as np
minval = np.min(a[np.nonzero(a)])
maxval = np.max(a[np.nonzero(a)])

其中a是你的数组。


3
@Shan:使用掩码数组可以避免a[np.nonzero(a)]所创建的副本--请参考我的答案。 - Sven Marnach

38

如果你的数组中可以选择“无效”值,最好使用nan而不是0

>>> a = numpy.array([1.0, numpy.nan, 2.0])
>>> numpy.nanmax(a)
2.0
>>> numpy.nanmin(a)
1.0

如果不可能,您可以使用数组掩码:
>>> a = numpy.array([1.0, 0.0, 2.0])
>>> masked_a = numpy.ma.masked_equal(a, 0.0, copy=False)
>>> masked_a.max()
2.0
>>> masked_a.min()
1.0

Josh使用高级索引的答案相比,这种方法的优点在于避免创建数组的副本。

2
@Sven:当我执行 ma.base is a 时,返回 false,因此看起来 ma 不仅仅是 a 的视图,而且内存中还有一份副本。或者我测试的方式不对吗? - JoshAdel
2
@JoshAdel:默认情况下,np.ma.masked_equal会复制a。要获取一个视图,请使用ma = np.ma.masked_equal(a, 0.0, copy=False) - unutbu
1
这对我非常有效 - 我有一个情况,需要检索最小/最大非零值的索引。 - Wojciech Migda
1
只是一个旁注:我觉得将视图(ma)的命名与用于创建它的模块(numpy.ma)相同,对于试图理解此代码的人来说是不必要的混淆,当它可以被命名为任何其他更具描述性的名称。例如,为什么不使用a_view - Brunox13
1
@Brunox13,我本来不觉得这会让人困惑,因为只有三行代码,所以谢谢你的反馈!我选择了masked_a - Sven Marnach
显示剩余5条评论

7

这里提供另一种掩码的方法,我认为更易于记忆(尽管它会复制数组)。对于本例,步骤如下:

>>> import numpy
>>> a = numpy.array([1.0, 0.0, 2.0])
>>> ma = a[a != 0]
>>> ma.max()
2.0
>>> ma.min()
1.0
>>> 

这适用于其他表达式,例如a > 0, numpy.isnan(a), ... 您可以使用标准运算符(+表示 OR,*表示 AND,-表示 NOT)组合掩码,例如:

# Identify elements that are outside interpolation domain or NaN
outside = (xi < x[0]) + (eta < y[0]) + (xi > x[-1]) + (eta > y[-1])
outside += numpy.isnan(xi) + numpy.isnan(eta)
inside = -outside
xi = xi[inside]
eta = eta[inside]

5

掩码数组 通常是专门为这些目的而设计的。您可以利用从数组中遮蔽零(或任何其他类型的遮罩,甚至比简单的相等性更复杂的遮罩),并且可以在掩码数组上执行大部分正常数组上执行的操作。您还可以指定要沿其查找最小值的轴:

import numpy.ma as ma
mx = ma.masked_array(x, mask=x==0)
mx.min()

示例输入:

x = np.array([1.0, 0.0, 2.0])

输出:

1.0

4
您可以使用生成器表达式来过滤掉零:

您可以使用生成器表达式来过滤掉零:
array = [-2, 0, -4, 0, -3, -2]
max(x for x in array if x != 0)

1
我认为OP在谈论numpy数组而不是Python列表。虽然您的解决方案对后者是正确的,但两者有所不同。我不会投反对票,只是让您知道。 - JoshAdel
啊,刚看到数组,没看到numpy标签。 - Chris Pickett
1
这对于numpy数组仍然有效,因此它是一个有效的答案。 对于像这样的小数组,它比numpy版本快得多。 - endolith

2

一个简单的方法是使用列表推导式来排除零。

>>> tup = (0, 1, 2, 5, 2)
>>> min([x for x in tup if x !=0])
1

1
问题的标题确实说“在numpy数组(或元组)中”。 - Wilduck
在标题中没有看到元组,只读了问题中的数组。我承认错误+1。我之前对你(和其他回答者)有些过激,因为人们会将numpy问题的解决方案发布为numpy列表,而它们并不是。这是我的个人偏好,因为numpy的解决方案通常更加高效。 - JoshAdel
我之前写错了一点:应该把它们当作是Python列表来处理。 - JoshAdel

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