Question

I'm looking to find the Python equivalent of the following Matlab statement:

vq interp1(x,y, xq,'nearest','extrap')

It looks as if interp(xq, x, y) works perfectly for linear interpolation/extrapolation.

I also looked at

F = scipy.interpolate.interp1d(x, y, kind='nearest')

which works perfectly for the nearest method, but will not perform extrapolation.

Is there anything else I've overlooked? Thanks.

Was it helpful?

Solution

For linear interpolation that will extrapolate using nearest interpolation, use numpy.interp. It does this by default.

For example:

yi = np.interp(xi, x, y)

Otherwise, if you just want nearest interpolation everywhere, as you describe, you can do it in the short, but inefficient way: (you can make this a one-liner, if you want)

def nearest_interp(xi, x, y):
    idx = np.abs(x - xi[:,None])
    return y[idx.argmin(axis=1)]

Or in a more efficient way using searchsorted:

def fast_nearest_interp(xi, x, y):
    """Assumes that x is monotonically increasing!!."""
    # Shift x points to centers
    spacing = np.diff(x) / 2
    x = x + np.hstack([spacing, spacing[-1]])
    # Append the last point in y twice for ease of use
    y = np.hstack([y, y[-1]])
    return y[np.searchsorted(x, xi)]

To illustrate the difference between numpy.interp and the nearest interpolation examples above:

import numpy as np
import matplotlib.pyplot as plt

def main():
    x = np.array([0.1, 0.3, 1.9])
    y = np.array([4, -9, 1])
    xi = np.linspace(-1, 3, 200)

    fig, axes = plt.subplots(nrows=2, sharex=True, sharey=True)
    for ax in axes:
        ax.margins(0.05)
        ax.plot(x, y, 'ro')

    axes[0].plot(xi, np.interp(xi, x, y), color='blue')
    axes[1].plot(xi, nearest_interp(xi, x, y), color='green')

    kwargs = dict(x=0.95, y=0.9, ha='right', va='top')
    axes[0].set_title("Numpy's $interp$ function", **kwargs)
    axes[1].set_title('Nearest Interpolation', **kwargs)

    plt.show()

def nearest_interp(xi, x, y):
    idx = np.abs(x - xi[:,None])
    return y[idx.argmin(axis=1)]

main()

enter image description here

OTHER TIPS

In later versions of SciPy (at least v0.19.1+), scipy.interpolate.interp1d has the option fill_value = “extrapolate”.

For example:

import pandas as pd
>>> s = pd.Series([1, 2, 3])
Out[1]: 
0    1
1    2
2    3
dtype: int64

>>> t = pd.concat([s, pd.Series(index=s.index + 0.1)]).sort_index()
Out[2]: 
0.0    1.0
0.1    NaN
1.0    2.0
1.1    NaN
2.0    3.0
2.1    NaN
dtype: float64

>>> t.interpolate(method='nearest')
Out[3]: 
0.0    1.0
0.1    1.0
1.0    2.0
1.1    2.0
2.0    3.0
2.1    NaN
dtype: float64

>>> t.interpolate(method='nearest', fill_value='extrapolate')
Out[4]: 
0.0    1.0
0.1    1.0
1.0    2.0
1.1    2.0
2.0    3.0
2.1    3.0
dtype: float64

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top