在numpy数组中插值NaN值

80 投票
14 回答
91618 浏览
提问于 2025-04-16 20:30

有没有什么简单的方法可以把numpy数组里所有的NaN值替换成(比如说)线性插值的值呢?

举个例子,

[1 1 1 nan nan 2 2 nan 0]

会被转换成

[1 1 1 1.3 1.6 2 2  1  0]

14 个回答

13

只需要使用numpy的逻辑与运算符和where语句,就可以进行一维插值。

import numpy as np
from scipy import interpolate

def fill_nan(A):
    '''
    interpolate to fill nan values
    '''
    inds = np.arange(A.shape[0])
    good = np.where(np.isfinite(A))
    f = interpolate.interp1d(inds[good], A[good],bounds_error=False)
    B = np.where(np.isfinite(A),A,f(inds))
    return B
29

我写了这段代码:

import numpy as np
nan = np.nan

A = np.array([1, nan, nan, 2, 2, nan, 0])

ok = -np.isnan(A)
xp = ok.ravel().nonzero()[0]
fp = A[-np.isnan(A)]
x  = np.isnan(A).ravel().nonzero()[0]

A[np.isnan(A)] = np.interp(x, xp, fp)

print A

它会输出

 [ 1.          1.33333333  1.66666667  2.          2.          1.          0.        ]
121

首先,我们定义一个简单的辅助函数,这样处理 NaN 的索引和逻辑索引会更简单:

import numpy as np

def nan_helper(y):
    """Helper to handle indices and logical indices of NaNs.

    Input:
        - y, 1d numpy array with possible NaNs
    Output:
        - nans, logical indices of NaNs
        - index, a function, with signature indices= index(logical_indices),
          to convert logical indices of NaNs to 'equivalent' indices
    Example:
        >>> # linear interpolation of NaNs
        >>> nans, x= nan_helper(y)
        >>> y[nans]= np.interp(x(nans), x(~nans), y[~nans])
    """

    return np.isnan(y), lambda z: z.nonzero()[0]

现在可以像这样使用 nan_helper(.)

>>> y= array([1, 1, 1, NaN, NaN, 2, 2, NaN, 0])
>>>
>>> nans, x= nan_helper(y)
>>> y[nans]= np.interp(x(nans), x(~nans), y[~nans])
>>>
>>> print y.round(2)
[ 1.    1.    1.    1.33  1.67  2.    2.    1.    0.  ]

---
虽然一开始看起来单独写一个函数来处理这些事情有点多余:

>>> nans, x= np.isnan(y), lambda z: z.nonzero()[0]

但从长远来看,这样做是值得的。

所以,每当你处理与 NaN 相关的数据时,记得把所有需要的(新的与 NaN 相关的)功能放在一些特定的辅助函数里。这样你的代码会更整洁、更易读,因为它遵循了简单易懂的写法。

插值确实是一个很好的例子,能展示如何处理 NaN,但类似的技巧在其他很多场合也会用到。

撰写回答