pythonnumpyinterpolationextrapolation

Extrapolate NaN values in a numpy array


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?


Solution

  • 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])