Blog

How interpolation is used in data science

Missing values, resampling, percentiles, SMOTE and learning rate warmup are all the same arithmetic. Plus the leakage trap that fakes good scores.


Interpolation rarely gets its own chapter in a data science course, and it runs underneath half your pipeline anyway. Filling a gap in a sensor feed, lining up two series recorded at different rates, computing a percentile, generating a synthetic training example, warming up a learning rate: the same few lines of arithmetic every time, under different names.

Six places you already meet it, and one mistake that inflates your validation scores.

1. Filling gaps in a time series

A logger reads 21.4 °C at 10:00 and 23.0 °C at 11:00, with a null at 10:10. Filling it linearly is obvious. Which linear fill you get depends on an argument most people leave at its default.

df.interpolate(method='linear') ignores your timestamps completely and treats the rows as evenly spaced. Three rows means the middle one counts as halfway:

21.4 + 0.5 × 1.6 = 22.20 °C

df.interpolate(method='time') looks at the actual clock. 10:10 is 10 minutes into a 60 minute gap, so the fraction is 10 ÷ 60 = 0.1667:

21.4 + 0.1667 × 1.6 = 21.4 + 0.2667 = 21.67 °C

Half a degree apart, from the same call on the same data. On irregularly sampled data the linear default is almost always the wrong one and it never complains. If your index holds timestamps, pass method='time'.

Two other arguments matter more than they look. limit caps how many nulls in a row get filled, which stops a three day outage turning into a smooth invented ramp that looks like real data. And limit_direction decides whether nulls at the very start and end get filled at all. Filling those is extrapolation, since there is nothing on one side to interpolate between.

2. Resampling and lining series up

Joining a series sampled every 5 minutes to one sampled every 90 seconds means putting both on a shared clock, which means interpolating at least one of them. Which direction you are going changes the right method.

Going to a finer grid genuinely needs interpolation, since you are inventing values between real observations. Linear is the safe default. Splines look nicer and can overshoot into values that are physically impossible, which matters when the quantity cannot go below zero.

Going to a coarser grid does not need interpolation at all. Aggregate instead: mean, sum, last or max depending on what the number means. Interpolating on the way down throws away information that aggregating would have kept.

3. Percentiles

Nearly every quantile function interpolates, and hardly anyone notices. Take the sorted values [2, 4, 6, 9] and ask NumPy for the 60th percentile with its default method. First it works out a position in the list:

h = (n − 1) × q = 3 × 0.6 = 1.8

Position 1.8 does not exist, so it interpolates between the values at positions 1 and 2, which are 4 and 6. Position 1.8 is 80 percent of the way from one to the other:

4 + 0.8 × (6 − 4) = 4 + 1.6 = 5.6

Your answer, 5.6, is not in the dataset and never was. Fine for a continuous measurement like a response time. Misleading for something countable, where a fractional value has no meaning. NumPy ships nine different methods for exactly this reason, and method='lower' or 'nearest' returns a value you actually observed.

4. Synthetic training examples

SMOTE, the standard fix for class imbalance, is interpolation with a different name. It picks a minority-class row, picks one of its nearest minority neighbours, and creates a new row somewhere on the line between them:

xnew = xi + λ(xneighbour − xi), with λ picked at random between 0 and 1

With a row at (2.0, 30), a neighbour at (3.0, 50) and λ = 0.4, the new row is (2.0 + 0.4, 30 + 8) = (2.4, 38).

Two of its weaknesses fall straight out of that formula. Categorical features break, because interpolating between category codes 2 and 5 gives you 3.2, which is not a category. And it assumes the space between two minority rows is also minority territory, which stops being true wherever the class boundary curves between them. You can see both problems in the arithmetic, before training anything.

5. Learning rate warmup

A linear warmup interpolates from 0 up to your target learning rate over the first N steps. With a target of 3e-4 and 1000 warmup steps, step 250 gives:

t = 250 ÷ 1000 = 0.25, so lr = 0 + 0.25 × 3e-4 = 7.5e-5

Cosine and polynomial schedules swap the straight blend for a different curve of t, but the structure is identical: a weight running from 0 to 1 that mixes a start value into an end value. The same pattern drives weight averaging, moving averages of model parameters, and walks between two points in an embedding space.

6. Resizing images and arrays

Every resize in a vision pipeline is bilinear or bicubic interpolation over the source pixels. Worth being deliberate about, because the choice changes what your model sees.

Bilinear smooths, which can wipe out thin structures like cracks, wires or text strokes. Nearest neighbour keeps the exact original values, which is mandatory for segmentation masks where the pixel value is a class label. Resize a mask bilinearly and you get pixels labelled 2.7, which belongs to no class at all.

The mistake: interpolation leakage

This one quietly makes your model look better than it is. If you interpolate the whole time series and then split it into train and test, the filled values near the boundary were computed using observations from both sides. Rows in your training set now contain information from the test period.

Your validation score improves and the gap only shows up in production, where future observations are not sitting there waiting to be averaged in.

Fix it by changing the order. Split first, then fill each split on its own, using only methods that look backward for anything that has to run live. Forward fill and time-weighted interpolation inside the training window are fine. Anything that reaches forward in time is not.

When to leave the gaps alone

When the missing value is itself a signal. A null because a device went offline during an incident is the most interesting row in your data. Smoothing it away deletes the thing you wanted to detect. Add a column flagging which values were imputed instead.

When the gap is long. Filling five minutes of a smooth signal is reasonable. Filling five days is making things up. Set a limit and let the rest stay null.

When the data is noisy. Interpolation passes exactly through every observation, including its measurement error. If you want a curve that ignores noise, you want smoothing or regression, which is a different job with a different goal.

When the variable cannot take in-between values. Categories, counts, and anything bounded should not be handed a fractional value.

None of this is difficult maths. It is the two-point formula applied with some attention to what the numbers mean. Check a single fill by hand in the interpolation calculator before trusting a pipeline to do a hundred thousand of them, and see the Python guide for which function to reach for.

Try it yourself

Run these numbers through the calculator and check the working step by step.

Open the calculator