首页 文章

用最接近的非NaN值替换NumPy数组中的NaN

提问于
浏览
17

我有一个NumPy数组 a 如下:

>>> str(a)
'[        nan         nan         nan  1.44955726  1.44628034  1.44409573\n  1.4408188   1.43657094  1.43171624  1.42649744  1.42200684  1.42117704\n  1.42040255  1.41922908         nan         nan         nan         nan\n         nan         nan]'

我想用最接近的非NaN值替换每个NaN,以便开头的所有NaN都设置为 1.449... ,并且最后的所有NaN都设置为 1.419... .

我可以看到如何针对这样的特定情况执行此操作,但我需要能够对任何长度的数组执行此操作,在数组的开头和结尾处有任何长度的NaN(在该数组中将没有NaN)中间的数字) . 有任何想法吗?

我可以用 np.isnan() 轻松找到NaN,但我无法弄清楚如何获得每个NaN最接近的值 .

7 回答

  • 1

    作为替代解决方案(这将对中间的数组 NaN 进行线性插值):

    import numpy as np
    
    # Generate data...
    data = np.random.random(10)
    data[:2] = np.nan
    data[-1] = np.nan
    data[4:6] = np.nan
    
    print data
    
    # Fill in NaN's...
    mask = np.isnan(data)
    data[mask] = np.interp(np.flatnonzero(mask), np.flatnonzero(~mask), data[~mask])
    
    print data
    

    这会产生:

    [        nan         nan  0.31619306  0.25818765         nan         nan
      0.27410025  0.23347532  0.02418698         nan]
    
    [ 0.31619306  0.31619306  0.31619306  0.25818765  0.26349185  0.26879605
      0.27410025  0.23347532  0.02418698  0.02418698]
    
  • 4

    这是一个使用简单的python迭代器的解决方案 . 它们实际上比 numpy.where 更有效,特别是对于大阵列!查看类似代码here的比较 .

    import numpy as np
    
    a = np.array([np.NAN, np.NAN, np.NAN, 1.44955726, 1.44628034, 1.44409573, 1.4408188, 1.43657094, 1.43171624,  1.42649744, 1.42200684, 1.42117704, 1.42040255, 1.41922908, np.NAN, np.NAN, np.NAN, np.NAN, np.NAN, np.NAN])
    
    mask = np.isfinite(a)
    
    # get first value in list
    for i in range(len(mask)):
        if mask[i]:
            first = i
            break
    
    # get last vaue in list
    for i in range(len(mask)-1, -1, -1):
        if mask[i]:
            last = i
            break
    
    # fill NaN with near known value on the edges
    a = np.copy(a)
    a[:first] = a[first]
    a[last + 1:] = a[last]
    
    print(a)
    

    输出:

    [1.44955726 1.44955726 1.44955726 1.44955726 1.44628034 1.44409573
     1.4408188  1.43657094 1.43171624 1.42649744 1.42200684 1.42117704
     1.42040255 1.41922908 1.41922908 1.41922908 1.41922908 1.41922908
     1.41922908 1.41922908]
    

    它仅替换此处请求的第一个和最后一个NaN .

  • 0

    我想用最接近的非NaN值替换每个NaN ......数字中间没有NaN

    以下将做到:

    ind = np.where(~np.isnan(a))[0]
    first, last = ind[0], ind[-1]
    a[:first] = a[first]
    a[last + 1:] = a[last]
    

    这是一个直接的 numpy 解决方案,不需要Python循环,没有递归,没有列表推导等 .

  • 35

    递归解决方案!

    def replace_leading_NaN(a, offset=0):
        if a[offset].isNaN():
            new_value = replace_leading_NaN(a, offset + 1)
            a[offset] = new_value
            return new_value
        else:
            return a[offset]
    
    def replace_trailing_NaN(a, offset=-1):
        if a[offset].isNaN():
            new_value = replace_trailing_NaN(a, offset - 1)
            a[offset] = new_value
            return new_value
        else:
            return a[offset]
    
  • 20

    我得到了这样的东西

    i = [i for i in range(len(a)) if not np.isnan(a[i])]
    a = [a[i[0]] if x < i[0] else (a[i[-1]] if x > i[-1] else a[x]) for x in range(len(a))]
    

    它有点笨拙虽然它被分成两行,嵌套内联如果在其中一行中 .

  • 0

    我遇到了这个问题,不得不为散乱的NaN找到一个自定义的解决方案 . 下面的函数将任何NaN替换为右边的第一个数字,如果不存在,则将它替换为左边的第一个数字 . 可以进行进一步的操作以用边界出现的平均值替换它 .

    import numpy as np
    
    Data = np.array([np.nan,1.3,np.nan,1.4,np.nan,np.nan])
    
    nansIndx = np.where(np.isnan(Data))[0]
    isanIndx = np.where(~np.isnan(Data))[0]
    for nan in nansIndx:
        replacementCandidates = np.where(isanIndx>nan)[0]
        if replacementCandidates.size != 0:
            replacement = Data[isanIndx[replacementCandidates[0]]]
        else:
            replacement = Data[isanIndx[np.where(isanIndx<nan)[0][-1]]]
        Data[nan] = replacement
    

    结果是:

    >>> Data
    array([ 1.3,  1.3,  1.4,  1.4,  1.4,  1.4])
    
  • 1

    NaN 具有与自身比较不同的有趣属性,因此我们可以快速找到非纳米元素的索引:

    idx = np.nonzero(a==a)[0]
    

    现在很容易用所需的值替换nans:

    for i in range(0, idx[0]):
        a[i]=a[idx[0]]
    for i in range(idx[-1]+1, a.size)
        a[i]=a[idx[-1]]
    

    最后,我们可以把它放在一个函数中:

    import numpy as np
    
    def FixNaNs(arr):
        if len(arr.shape)>1:
            raise Exception("Only 1D arrays are supported.")
        idxs=np.nonzero(arr==arr)[0]
    
        if len(idxs)==0:
            return None
    
        ret=arr
    
        for i in range(0, idxs[0]):
            ret[i]=ret[idxs[0]]
    
        for i in range(idxs[-1]+1, ret.size):
            ret[i]=ret[idxs[-1]]
    
        return ret
    

    edit

    哎哟,来自C我总是忘记列表范围... @ aix的解决方案比我的C ish循环更优雅和高效,使用它而不是我的 .

相关问题