numpy数组中的nan与标量的不等比较

21

我正在尝试将数组中低于某个阈值的成员设置为nan。这是QA/QC过程的一部分,输入数据可能已经有nan的槽。

例如,我的阈值可能为-1000,因此我想将以下数组中的-3000设置为nan:

x = np.array([np.nan,1.,2.,-3000.,np.nan,5.])

这是需要翻译的内容:

以下是:

x[x < -1000.] = np.nan

产生了正确的行为,但也会出现一个运行时警告,但禁用警告的开销较大。

warnings.filterwarnings("ignore")
...
warnints.resetwarnings()

这有点笨重且可能有些不安全。

尝试使用以下高级索引两次进行索引不会产生任何效果:

nonan = np.where(~np.isnan(x))[0]
x[nonan][x[nonan] < -1000.] = np.nan

我猜想这是由于整数索引或重复索引的使用导致了副本的生成。
有没有相对简单的解决方案?在处理过程中使用掩码数组也可以,但最终产品必须是ndarray,并且不能引入新的依赖项。谢谢。
5个回答

18

一种选择是使用 numpy.errstate 来禁用相关警告:

with numpy.errstate(invalid='ignore'):
    ...

要全局关闭相关警告,请使用 numpy.seterr

谢谢。我认为可以使用警告过滤器在警告中找到更安全的方法: - Eli S
warnings.filterwarnings("ignore") ,然后之后 - Eli S
这也是一个全局变更...如果立即重置,则可以说是相当安全的。然而,正如我给Jamie的提示一样,我知道禁用方法。我正在寻找一些没有这种开销的东西。但是我认为你的答案可能会帮助很多人。 - Eli S
2
你可以使用errstate来进行偏好设置。 - Mad Physicist

17

任何比较(除了!=)NaN与任何非NaN值都会返回False:

>>> x < -1000
array([False, False, False,  True, False, False], dtype=bool)

所以您可以简单地忽略数组中已经存在 NaN 的事实,并执行以下操作:

>>> x[x < -1000] = np.nan
>>> x
array([ nan,   1.,   2.,  nan,  nan,   5.])

编辑 我运行上述代码时没有看到任何警告,但如果您确实需要避免NaN值,可以进行类似以下方式的处理:

mask = ~np.isnan(x)
mask[mask] &= x[mask] < -1000
x[mask] = np.nan

3
我同意你的逻辑,很高兴你指出这不是通常的NaN不等于NaN问题。但当我尝试这个时,问题在于它会产生一个运行时警告。一种选择是导入警告并捕获它,但这需要很多打字和额外工作量。我希望有一种更经济的替代方案。 - Eli S
有人知道为什么 np.nan 允许比较吗?(始终评估为 False 而不像 None < x 一样引发 TypeError 或其他错误)。如果一些 NaNs 从 NumPy 数组中逃出到普通 Python 变量,并开始使用普通 Python 方法和表达式,则会导致各种问题。 - Bill
根据IEEE 754的规定,这就是NaN应该做的,你将得到相同的行为,例如从float('nan'):https://en.wikipedia.org/wiki/NaN#Comparison_with_NaN - Jaime

9

np.less()函数具有一个where参数,用于控制操作的应用位置。因此你可以这样做:

x[np.less(x, -1000., where=~np.isnan(x))] = np.nan

1
你可以简单地使用 where=np.isfinite(x) - Chris

2

我个人忽略了已经给出的使用np.errstate上下文管理器的警告,因为代码清晰度值得额外的时间,但这里有一个替代方案。

# given
x = np.array([np.nan, 1., 2., -3000., np.nan, 5.])

# apply NaNs as desired
mask = np.zeros(x.shape, dtype=bool)
np.less(x, -1000, out=mask, where=~np.isnan(x))
x[mask] = np.nan

# expected output and comparison
y = np.array([np.nan, 1., 2., np.nan, np.nan, 5.])
assert np.allclose(x, y, rtol=0., atol=1e-14, equal_nan=True)

NumPy中的lessufunc接受可选参数where,并且仅在为true时对其进行评估,与np.where函数不同,该函数会评估两个选项,然后选择相关选项。您可以使用out参数设置未为true时的所需输出。


请注意,此处需要使用 out=mask 关键字参数才能正常工作。否则,np.less 将在跳过的位置返回 True。 - Will Holmgren

2
有点晚了,但这是我的做法:
x = np.array([np.nan,1.,2.,-3000.,np.nan,5.]) 

igood=np.where(~np.isnan(x))[0]
x[igood[x[igood]<-1000.]]=np.nan

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