【问题标题】:How to get rid of "RuntimeWarning: invalid value encountered in greater"如何摆脱“RuntimeWarning:遇到更大的无效值”
【发布时间】:2018-04-30 14:26:48
【问题描述】:

这个问题与很多与警告RuntimeWarning: invalid value encountered in greater/less/etc相关的问题非常相似

但是,我找不到针对我的特定问题的解决方案,我认为应该有一个解决方案。

所以,我有一个类似于这个的numpy.ndarray

array([[ nan,   1.,  nan, ...,  nan,  nan,  nan],
       [ nan,  nan,  nan, ...,  nan,  nan,  nan],
       [ nan,  nan,  nan, ...,  nan,  nan,  nan],
       ..., 
       [ nan,  nan,  nan, ...,  nan,  nan,  nan],
       [ nan,  nan,  nan, ...,  nan,  nan,  nan],
       [ nan,  nan,  nan, ...,  nan,  nan,  nan]])

我想计算array > 0.5,它给出了我想要的结果,但警告与nan进行比较:

__main__:1: RuntimeWarning: invalid value encountered in greater
Out[68]: 
array([[False,  True, False, ..., False, False, False],
       [False, False, False, ..., False, False, False],
       [False, False, False, ..., False, False, False],
       ..., 
       [False, False, False, ..., False, False, False],
       [False, False, False, ..., False, False, False],
       [False, False, False, ..., False, False, False]], dtype=bool)

我基本上想计算array > 0.5,但没有出现警告。

我的限制:

  • 我确实 只想用 with np.errstate(invalid='ignore'): 抑制警告
  • 我需要维护原始数组,因此无法更改。

我想出了一个简单的解决方案:

  • 更改原始矩阵 (array[np.isnan(array)] = -np.inf) 中的 nan,在我进行比较后将其恢复 (array[array == -np.inf] = np.nan)

但我认为,当(我认为)应该存在一种直接的方式来立即执行此操作时,所有这些计算只是浪费时间。我一直在探索numpy.ma 模块和numpy.where 函数,但是我找不到我想要的这种“直接”解决方案。

对此有什么想法吗?

【问题讨论】:

  • 制作比较函数 (value != nan) 和 (value > 0.5)
  • @AlexvonBrandenfels 您的解决方案不起作用。首先,我必须将nan 更改为numpy.nan。但即使在那之后我还是有一个错误:ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
  • “我不想仅仅取消警告” - 为什么不呢?
  • @user2357112 因为我不认为这是正确的。我正在以 3 值逻辑进行比较,因此实际上将 NaN 与其他值进行比较的结果可能是错误的或其他值。在 numpy 的未来版本中,这个结果可能会改变,因此我想确保我总是有一个预期的结果
  • “在 numpy 的未来版本中,这个结果可能会改变”——这种情况极不可能发生,如果发生了,无论如何你都必须重新考虑所有的 NaN 处理。

标签: python-3.x numpy


【解决方案1】:

每当比较包含至少一个 NaN 的数组时,您都会收到该警告。解决方案是使用masking 仅比较非NaN 元素,我们将尝试在comparison based NumPy ufuncs 的帮助下有一个通用的解决方案来涵盖所有类型的比较,如下所示 -

def compare_nan_array(func, a, thresh):
    out = ~np.isnan(a)
    out[out] = func(a[out] , thresh)
    return out

想法是:

  • 获取非 NaN 的掩码。

  • 使用它从输入数组中获取非 NaN 值。然后执行所需的比较(大于、大于等于等)以获得另一个掩码,它表示被掩码位置的比较掩码输出。

  • 使用它来细化非 NaN 的掩码,这是最终输出。

示例运行 -

In [41]: np.random.seed(0)

In [42]: a = np.random.randint(0,9,(4,5)).astype(float)

In [43]: a.ravel()[np.random.choice(a.size, 16, replace=0)] = np.nan

In [44]: a
Out[44]: 
array([[ nan,  nan,  nan,  nan,  nan],
       [ nan,  nan,  nan,   4.,   7.],
       [ nan,  nan,  nan,   1.,  nan],
       [ nan,   7.,  nan,  nan,  nan]])

In [45]: a > 5  # Shows warning with the usual comparison
__main__:1: RuntimeWarning: invalid value encountered in greater
Out[45]: 
array([[False, False, False, False, False],
       [False, False, False, False,  True],
       [False, False, False, False, False],
       [False,  True, False, False, False]], dtype=bool)

# With suggested masking based method
In [46]: compare_nan_array(np.greater, a, 5)
Out[46]: 
array([[False, False, False, False, False],
       [False, False, False, False,  True],
       [False, False, False, False, False],
       [False,  True, False, False, False]], dtype=bool)

让我们通过测试lesser than 5 来测试通用行为 -

In [47]: a < 5
__main__:1: RuntimeWarning: invalid value encountered in less
Out[47]: 
array([[False, False, False, False, False],
       [False, False, False,  True, False],
       [False, False, False,  True, False],
       [False, False, False, False, False]], dtype=bool)

In [48]: compare_nan_array(np.less, a, 5)
Out[48]: 
array([[False, False, False, False, False],
       [False, False, False,  True, False],
       [False, False, False,  True, False],
       [False, False, False, False, False]], dtype=bool)

【讨论】:

  • 该死!解决方案实际上非常简单。我一直在关注您的所有编辑,嗯,非常感谢,这正是我想要的!
  • 但是可读性降低了。将其设置为默认方式怎么样?
  • 这不是我所说的“让警告消失”。它小心地避免引发此警告的操作。它在代码和运行时都有开销。但是,除了破解 NumPy 的源代码之外,您实际上可以做到 np.seterr(invalid='ignore')
  • @TomaszGandor OP 已经尝试过,但不想这样做。它在问题的My restrictions: 部分下。
  • 当您尝试从具有nan 值的数组中获取符号时,也可以将解决方案应用于np.sign()。错误为RuntimeWarning: invalid value encountered in sign。代替df['b'] = np.sign(df['a']),您可以使用dfS['b'] = evaluate_nan_array(np.sign, df['a']) where def evaluate_nan_array(func, a): out = ~np.isnan(a) out[out] = func(a[out]) return out
【解决方案2】:

有一个更好的方法 - 你不想永远隐藏警告,因为它可以帮助你以后发现其他错误。

遵循此问题中的建议:RuntimeWarning: invalid value encountered in divide

正确的方法:

如果结果是你想要的,你可以写:

with np.errstate(invalid='ignore'):
    result = (array > 0.5)

# ... use result, and your warnings are not suppressed.

另一种错误的方式:

否则,您可以通过复制数组来满足您的限制:

to_compare = array.copy()
to_compare[np.isnan(to_compare)] = 0.5  # you don't need -np.inf, anything <= 0.5 is OK
result = (to_compare > 0.5)

而且您不需要“恢复”数组中的 NaN。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-18
    • 2021-12-28
    • 2020-08-14
    • 2019-04-10
    • 1970-01-01
    • 1970-01-01
    • 2016-10-13
    相关资源
    最近更新 更多