【问题标题】:removing pairs of elements from numpy arrays that are NaN (or another value) in Python从 Python 中为 NaN(或其他值)的 numpy 数组中删除元素对
【发布时间】:2011-02-11 08:04:33
【问题描述】:

我在 numpy 中有一个包含两列的数组。例如:

a = array([[1, 5, nan, 6],
           [10, 6, 6, nan]])
a = transpose(a)

我想有效地遍历两列 a[:, 0] 和 a[:, 1] 并删除满足特定条件的任何对,在这种情况下,如果它们是 NaN。我能想到的明显方法是:

new_a = []
for val1, val2 in a:
  if val2 == nan or val2 == nan:
    new_a.append([val1, val2])

但这似乎很笨拙。这样做的 pythonic numpy 方式是什么?

谢谢。

【问题讨论】:

    标签: python arrays numpy scipy


    【解决方案1】:

    如果您只想获取没有 NAN 的行,这就是您需要的表达式:

    >>> import numpy as np
    >>> a[~np.isnan(a).any(1)]
    array([[  1.,  10.],
           [  5.,   6.]])
    

    如果您想要其元素中没有特定数字的行,例如5:

    >>> a[~(a == 5).any(1)]
    array([[  1.,  10.],
           [ NaN,   6.],
           [  6.,  NaN]])
    

    后者显然等价于

    >>> a[(a != 5).all(1)]
    array([[  1.,  10.],
           [ NaN,   6.],
           [  6.,  NaN]])
    

    说明: 让我们首先创建您的示例输入

    >>> import numpy as np
    >>> a = np.array([[1, 5, np.nan, 6],
    ...               [10, 6, 6, np.nan]]).transpose()
    >>> a
    array([[  1.,  10.],
           [  5.,   6.],
           [ NaN,   6.],
           [  6.,  NaN]])
    

    这决定了哪些元素是 NAN

    >>> np.isnan(a)
    array([[False, False],
           [False, False],
           [ True, False],
           [False,  True]], dtype=bool)
    

    这标识了哪些行具有任何为真的元素

    >>> np.isnan(a).any(1)
    array([False, False,  True,  True], dtype=bool)
    

    由于我们不想要这些,我们否定最后一个表达式:

    >>> ~np.isnan(a).any(1)
    array([ True,  True, False, False], dtype=bool)
    

    最后我们使用布尔数组来选择我们想要的行:

    >>> a[~np.isnan(a).any(1)]
    array([[  1.,  10.],
           [  5.,   6.]])
    

    【讨论】:

    • +1:超级清晰有用的解释,我喜欢 ~np.isnan,因为它说明了你在做什么。
    • 多么棒的答案
    【解决方案2】:

    您可以将数组转换为masked array,并使用compress_rows method

    import numpy as np
    a = np.array([[1, 5, np.nan, 6],
               [10, 6, 6, np.nan]])
    a = np.transpose(a)
    print(a)
    # [[  1.  10.]
    #  [  5.   6.]
    #  [ NaN   6.]
    #  [  6.  NaN]]
    b=np.ma.compress_rows(np.ma.fix_invalid(a))
    print(b)
    # [[  1.  10.]
    #  [  5.   6.]]
    

    【讨论】:

    • +1:哇!我不经常看到使用和建议使用掩码数组!不错!
    【解决方案3】:

    不要贬低 ig0774 的答案,这是完全有效的 Pythonic,实际上是用普通 Python 做这些事情的正常方式,但是:numpy 支持布尔索引系统,它也可以完成这项工作。

    new_a = a[(a==a).all(1)]
    

    我不确定哪种方式更有效(或执行速度更快)。

    如果您想使用不同的条件来选择行,则必须进行更改,具体如何取决于条件。如果可以独立评估每个数组元素,您可以将a==a 替换为适当的测试,例如消除所有大于 100 的行,您可以这样做

    new_a = a[(a<=100).all(1)]
    

    但是,如果您尝试做一些涉及一行​​中所有元素的花哨的事情(例如消除总和超过 100 的所有行),则可能会更复杂。如果是这种情况,如果您想分享您的确切情况,我可以尝试编辑更具体的答案。

    【讨论】:

    • +1:用于矢量化方法。这几乎总是更快,是使用 numpy 的主要原因之一。
    【解决方案4】:

    我认为list comprehensions 应该这样做。例如,

    new_a = [(val1, val2) for (val1, val2) in a if math.isnan(val1) or math.isnan(val2)]
    

    【讨论】:

    • 您实际上需要进行类似val1 != val1 的测试,因为nan == nan 返回false。但是+1。
    • 我编辑了上面的内容......老实说,我从来不需要NaN,所以我主要是在解决构建列表的形式。根据此处的文档:docs.python.org/library/math.html#math.isnan,我认为这应该可行...
    • 不应该是:...在不是 math isnan(val1) 而不是 math.isnan(val2) 的地方吗?
    • 你做的 SQL 太多了。 :) 使用 'if' 而不是 'where'。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-21
    • 2017-04-11
    • 2015-05-21
    • 2019-12-22
    • 2015-06-08
    • 1970-01-01
    相关资源
    最近更新 更多