I have two values and know their index in an array full of nans. I want to interpolate / extrapolate all the nan's
import numpy as np
y = np.array([np.nan, np.nan, 0.75, np.nan, np.nan, np.nan, np.nan, np.nan, 2.25])
With the help of this answer I write the following:
nans, x = np.isnan(y), lambda z: z.nonzero()[0]
y[nans] = np.interp(x(nans), x(~nans), y[~nans])
My output looks as follows:
[0.75 0.75 0.75 1. 1.25 1.5 1.75 2. 2.25]
However, I would like it to be:
[0.25 0.5 0.75 1. 1.25 1.5 1.75 2. 2.25]
The increment is always a constant.
When I read the documentation of np.iterp
I see that I can specify the input-parameters left
and right
. If I don't specify left
, the value to return for x < xp[0] is fp[0].
How can I specify left
and right
in order to get the desired output?
CodePudding user response:
np.interp
doesn't seem to make extrapolation,
but scipy.interpolate.interp1d
does.
The arguments to give are a bit different, you can make it a function for your particular case:
import numpy as np
from scipy.interpolate import interp1d
def interp_nans(y, x=None):
if x is None:
x = np.arange(len(y))
nans = np.isnan(y)
interpolator = interp1d(
x[~nans],
y[~nans],
kind="linear",
fill_value="extrapolate",
assume_sorted=True,
)
return interpolator(x)
Check that it works:
y = np.array([np.nan, np.nan, 0.75, np.nan, np.nan, np.nan, np.nan, np.nan, 2.25])
expected = np.array([0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25])
result = interp_nans(y)
assert np.array_equal(result, expected)
CodePudding user response:
You can't specify left
and right
to achieve extrapolation with interp
, they are just constant values.
If you prefer a pure numpy solution, you can linearly extrapolate based on the first/last two values of the interpolated array:
def extrap(x, xp, fp):
m = (fp[1] - fp[0]) / (xp[1] - xp[0])
n = fp[0] - m * xp[0]
result = m * x[x < xp[0]] n
m = (fp[-1] - fp[-2]) / (xp[-1] - xp[-2])
n = fp[-1] - m * xp[-1]
return np.concatenate([result, m * x[x > xp[-1]] n])
(you may want to add verification of len(xp) > 1
and len(xp) == len(yp)
)
Example:
y = np.array([np.nan, np.nan, 0.75, np.nan, np.nan, np.nan, np.nan, np.nan, 2.25, np.nan])
nans, x = np.isnan(y), lambda z: z.nonzero()[0]
y[nans] = np.interp(x(nans), x(~nans), y[~nans], np.nan, np.nan)
nans, x = np.isnan(y), lambda z: z.nonzero()[0]
y[nans] = extrap(x(nans), x(~nans), y[~nans])
Result
array([0.25, 0.5 , 0.75, 1. , 1.25, 1.5 , 1.75, 2. , 2.25])