Python gives you three good options and several ways to get a wrong number with no error message. Here is what each one does, what happens when your target falls outside the data, and when the extra dependency is worth it.
The quick answer
Use
np.interp(x, xp, fp)for straight-line interpolation. It is fast, it works on arrays, and it needs nothing beyond NumPy.Add
left=np.nan, right=np.nanunless you actively want it to return the nearest endpoint value for out-of-range input, which is what it does by default and rarely what you meant.
numpy.interp
Pass your target, the known x values, and the known y values:
xp = [1, 2, 3]fp = [10, 20, 25]
np.interp(2.5, xp, fp) → 22.5
Check it by hand: 2.5 is halfway between 2 and 3, where the values are 20 and 25, so 20 + 0.5 × 5 = 22.5. Pass an array of targets and you get an array back, which is far faster than looping in Python.
Two requirements that are documented and still catch people.
xp has to be increasing. There is no check for this. Give it unsorted input and it returns
numbers that look fine and mean nothing. Sort first with order = np.argsort(xp) and index both
arrays by it.
NaNs spread. One NaN in your y values poisons the two intervals either side of it. Filter them out before interpolating rather than cleaning up afterwards.
What it does past the end of your data
np.interp(5, [1, 2, 3], [10, 20, 25]) → 25.0No error, no warning. It returns the last y value and keeps returning it forever. That is a reasonable default for signal processing and a dangerous one for analysis, because a chart of the result shows a flat line that reads as a genuine plateau in your data rather than as missing input.
Make it visible instead:
np.interp(5, xp, fp, left=np.nan, right=np.nan) → nanA NaN in a plot leaves a gap you notice immediately. This matters for the reason set out in interpolation vs extrapolation: past the edge of your data, nothing keeps the answer honest.
scipy.interpolate.interp1d
This builds a function you call repeatedly, and it supports several kinds:
'linear', 'nearest', 'quadratic', 'cubic', plus
'previous' and 'next' for step behaviour.
f(2.5)
Building once and calling many times is the point of it. For a single value, np.interp is
simpler and quicker.
Its behaviour at the edges is the opposite of NumPy's, and better: out-of-range input raises a ValueError.
You can turn that off with bounds_error=False, fill_value='extrapolate', but think before you
do. Extrapolating a cubic is a bad idea, because the curve on the last segment owes your data nothing once it
leaves the range.
SciPy now lists interp1d as legacy. New code should use np.interp for linear work,
CubicSpline or PchipInterpolator for smooth curves, and
make_interp_spline for anything else. Existing code that uses it is not broken and does not need
rewriting.
CubicSpline
from scipy.interpolate import CubicSplinecs = CubicSpline(xp, fp, bc_type='natural')
cs(2.5) # the value
cs(2.5, 1) # the slope there
cs.integrate(1, 3) # area under the curve
You get the slope and the area for free, which is the main reason to keep a spline object around rather than a plain array of interpolated numbers.
The bc_type argument controls what the curve does at the two ends. 'not-a-knot' is
the default and usually looks best on real data. 'natural' makes the curve stop bending at the
ends, and 'clamped' makes it flat there. The
spline tutorial works the natural case through by hand
if you want to see what the object is doing internally.
Use PchipInterpolator instead when your data only goes one direction and has to stay that way.
A cubic spline can dip below your data between two points, which produces a negative value in a series that
is physically positive. PchipInterpolator gives up a little smoothness and promises not to overshoot.
pandas
s.interpolate(method='time', limit=3, limit_area='inside')
On a series indexed by timestamps, method='linear' ignores the timestamps and pretends the rows
are evenly spaced, which is wrong for irregular data. method='time' uses the real gaps.
limit stops a long outage becoming an invented ramp, and limit_area='inside'
prevents it filling leading and trailing gaps, which would be extrapolation. The surrounding pitfalls,
including the leakage one, are covered in
interpolation in data science.
Writing it yourself
For one value with no dependencies:
def lerp(x, x1, y1, x2, y2):if x2 == x1:
return y1
t = (x - x1) / (x2 - x1)
return (1 - t) * y1 + t * y2
The first two lines handle duplicate x values, which do happen in real tables and otherwise blow up with a ZeroDivisionError somewhere deep in a loop.
The last line uses (1 - t) * y1 + t * y2 rather than y1 + t * (y2 - y1) because it
returns exactly y1 at t = 0 and exactly y2 at t = 1 in floating point. Recent Python versions also ship
math.lerp if all you need is the blend.
Picking one
| What you need | Use |
|---|---|
| Fast straight-line interpolation on arrays | np.interp |
| An error when input falls outside the data | interp1d, default settings |
| A smooth curve, slopes, or areas | CubicSpline |
| Data that must never go backwards | PchipInterpolator |
| A time series with gaps | Series.interpolate(method='time') |
| Values on a 2D grid | RegularGridInterpolator |
| Scattered points in 2D or 3D | griddata or RBFInterpolator |
Whichever you pick, check one value by hand the first time you use it. The interpolation calculator is quick for that, and one verified number catches unsorted input and unit mix-ups before they end up in a report.