在numpy数组中插值NaN值
有没有什么简单的方法可以把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,但类似的技巧在其他很多场合也会用到。