Interpolation & Filling Gaps
Reviewed & published by Brayan K
Interpolation estimates missing values by drawing a smooth line between the known points around them, so a gap between 1 and 4 becomes 2 and 3 instead of staying blank.
Part of the free Pandas course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
You'll learn df.interpolate() with the linear and time methods, the limit and limit_direction controls, and how it differs from plain fillna(ffill/bfill).
What You'll Learn in This Lesson
- Estimate gaps with interpolate(method="linear")
- Weight gaps by elapsed time with method="time"
- Cap fills with limit and limit_direction
- Fill leading gaps with limit_direction="both"
- How interpolate differs from ffill / bfill
- Choose the right tool for the right gap
1 Linear Interpolation — Connect the Dots
The default interpolate() uses linear interpolation: it draws a straight line between each pair of known values and reads off the missing points along that line. A gap between 1.0 and 4.0 spread over two missing rows becomes 2.0 and 3.0 — evenly spaced steps.
import pandas as pd
import numpy as np
s = pd.Series([1.0, np.nan, np.nan, 4.0, 5.0])
s.interpolate() # -> 1, 2, 3, 4, 5import pandas as pd
import numpy as np
s = pd.Series([1.0, np.nan, np.nan, 4.0, 5.0])
print(s)
# Linear interpolation fills the gap with even steps
print(s.interpolate())
# ✅ Expected output:
# 0 1.0
# 1 NaN
# 2 NaN
# 3 4.0
# 4 5.0
# dtype: float64
# 0 1.0
# 1 2.0
# 2 3.0
# 3 4.0
# 4 5.0
# dtype: float642 Time-Aware Interpolation — method="time"
When the index is a DatetimeIndex with uneven spacing, linear interpolation gives the wrong answer because it treats every gap as equal. method="time" weights the estimate by the real elapsed time, so a missing value that sits closer to a later reading lands closer to that reading's value.
idx = pd.to_datetime(["2024-01-01", "2024-01-03", "2024-01-08"])
ts = pd.Series([10.0, np.nan, 60.0], index=idx)
ts.interpolate(method="time")
# Jan 03 is only 2 of 7 days along, so it lands near 24.3, not the
# midpoint 35 that plain "linear" would give.import pandas as pd
import numpy as np
idx = pd.to_datetime(["2024-01-01", "2024-01-03", "2024-01-08"])
ts = pd.Series([10.0, np.nan, 60.0], index=idx)
# Weighted by real elapsed days
print(ts.interpolate(method="time"))
# Compare: plain linear ignores the spacing -> midpoint 35.0
print(ts.interpolate(method="linear"))
# ✅ Expected output:
# 2024-01-01 10.000000
# 2024-01-03 24.285714
# 2024-01-08 60.000000
# dtype: float64
# 2024-01-01 10.0
# 2024-01-03 35.0
# 2024-01-08 60.0
# dtype: float643 Limits, Direction, and vs ffill / bfill
Two controls keep interpolation honest, and one comparison keeps it in context:
- limit=n — fill at most n consecutive NaNs in a run; longer gaps stay partly blank.
- limit_direction — by default only "forward" gaps between known points are filled. Pass "both" to also fill leading and trailing NaNs by extending the nearest value.
- ffill() / bfill() — these copy the last (or next) known value rather than estimating a trend. Flat carry-forward, not a slope.
s = pd.Series([1.0, np.nan, np.nan, np.nan, 5.0])
s.interpolate(limit=1) # only the first NaN of the run is filled
s.ffill() # carry 1.0 forward across the whole gapimport pandas as pd
import numpy as np
s = pd.Series([1.0, np.nan, np.nan, np.nan, 5.0])
# interpolate with limit=1 -> only the FIRST gap value is filled
print(s.interpolate(limit=1))
# ffill -> copies 1.0 forward (flat), no slope
print(s.ffill())
# ✅ Expected output:
# 0 1.0
# 1 2.0
# 2 NaN
# 3 NaN
# 4 5.0
# dtype: float64
# 0 1.0
# 1 1.0
# 2 1.0
# 3 1.0
# 4 5.0
# dtype: float64import pandas as pd
import numpy as np
# A sensor that logged readings but missed a few samples
sensor = pd.Series([20.0, np.nan, np.nan, 26.0, np.nan, 30.0])
# 🎯 YOUR TURN:
# The values rise smoothly, so estimate the missing points with a
# straight-line (linear) fill. Fill in the ONE blank with the method name.
print(sensor.____())
# Expected output:
# 0 20.0
# 1 22.0
# 2 24.0
# 3 26.0
# 4 28.0
# 5 30.0
# dtype: float64! Common Errors (And How to Fix Them)
❌ Leading NaNs stay empty
A gap at the very start has nothing earlier to interpolate from:
pd.Series([np.nan, np.nan, 3.0, 4.0]).interpolate()
# -> NaN, NaN, 3.0, 4.0 (the leading gap is untouched)✅ Fix: extend both directions:
pd.Series([np.nan, np.nan, 3.0, 4.0]).interpolate(limit_direction="both")
# -> 3.0, 3.0, 3.0, 4.0❌ method="time" on a non-datetime index
pd.Series([1, np.nan, 3]).interpolate(method="time") # ❌ ValueError✅ Fix: give it a DatetimeIndex first, or use "linear":
ts = pd.Series([1, np.nan, 3], index=pd.to_datetime(
["2024-01-01", "2024-01-02", "2024-01-04"]))
ts.interpolate(method="time") # ✅🎯 Mini Challenge: Three Ways to Fill Temperatures
A weather log has irregular daily gaps. Fill the same series three ways and compare.
- Linear interpolation (ignores spacing)
- Time interpolation (weights by elapsed days)
- Forward fill (flat carry-forward)
import pandas as pd
import numpy as np
idx = pd.to_datetime(["2024-06-01", "2024-06-02", "2024-06-05", "2024-06-06"])
temps = pd.Series([15.0, np.nan, np.nan, 27.0], index=idx)
print(temps.interpolate(method="linear"))
# Expected:
# 2024-06-01 15.0
# 2024-06-02 19.0
# 2024-06-05 23.0
# 2024-06-06 27.0
print(temps.interpolate(method="time"))
# Expected:
# 2024-06-01 15.0
# 2024-06-02 17.4
# 2024-06-05 24.6
# 2024-06-06 27.0
print(temps.ffill())
# Expected:
# 2024-06-01 15.0
# 2024-06-02 15.0
# 2024-06-05 15.0
# 2024-06-06 27.0
# ✅ Expected output:
# 2024-06-01 15.0
# 2024-06-02 19.0
# 2024-06-05 23.0
# 2024-06-06 27.0
# dtype: float64
# 2024-06-01 15.0
# 2024-06-02 17.4
# 2024-06-05 24.6
# 2024-06-06 27.0
# dtype: float64
# 2024-06-01 15.0
# 2024-06-02 15.0
# 2024-06-05 15.0
# 2024-06-06 27.0
# dtype: float64❓ Frequently Asked Questions
Lesson complete — your gaps are filled intelligently!
You can estimate missing values with interpolate() (linear and time), cap fills with limit and limit_direction, and pick between estimating a trend and a flat ffill/bfill.
Practice quiz
What does interpolate() do to missing values?
- Deletes the rows
- Estimates them by drawing a line between known points
- Replaces them with 0
- Leaves them as NaN
Answer: Estimates them by drawing a line between known points. interpolate estimates gaps from the surrounding known values.
What is the default method used by interpolate()?
- time
- polynomial
- nearest
- linear
Answer: linear. The default is linear interpolation: a straight line between known points.
For pd.Series([1.0, NaN, NaN, 4.0, 5.0]).interpolate(), what fills the two gaps?
- 2.0 and 3.0
- 1.0 and 1.0
- 0.0 and 0.0
- 4.0 and 4.0
Answer: 2.0 and 3.0. Linear interpolation splits the gap into even steps: 2.0 and 3.0.
What does method='time' weight the estimate by?
- The row count
- Alphabetical order
- The actual elapsed time between known points
- The column width
Answer: The actual elapsed time between known points. method='time' weights by real elapsed time, so it needs a datetime index.
Why are leading NaNs still NaN after a default interpolate()?
- A bug in pandas
- There is no earlier value to interpolate from
- Leading NaNs are always deleted
- interpolate ignores floats
Answer: There is no earlier value to interpolate from. A gap at the very start has nothing earlier to interpolate from, so it stays NaN.
How do you also fill leading and trailing gaps?
- limit=0
- method='edge'
- fill_both=True
- limit_direction='both'
Answer: limit_direction='both'. limit_direction='both' extends the nearest value to fill leading/trailing NaNs.
What does the limit parameter control?
- How many consecutive NaNs in a run get filled
- The maximum value allowed
- The number of decimal places
- The index length
Answer: How many consecutive NaNs in a run get filled. limit caps how many NaNs in a row are filled; longer gaps stay partly blank.
How do ffill() and bfill() differ from interpolate()?
- They are faster only
- They copy the last/next known value instead of estimating a trend
- They only work on dates
- They sort the data first
Answer: They copy the last/next known value instead of estimating a trend. ffill/bfill carry a value flat across the gap rather than estimating a slope.
Calling interpolate(method='time') on a plain RangeIndex causes what?
- It silently uses linear
- It returns the input unchanged
- A ValueError
- It fills with zeros
Answer: A ValueError. method='time' requires a datetime (or numeric) index, otherwise it raises a ValueError.
Which tool fits step-like data such as a status that stays the same until it changes?
- interpolate(method='time')
- interpolate(method='linear')
- describe()
- ffill() / bfill()
Answer: ffill() / bfill(). Use ffill/bfill for step-like data; interpolate is for smoothly changing measurements.
Continue this course
- Previous: Time Series Resampling (resample, asfreq)
- Next: Exploding Lists into Rows (explode) — Turn a column of lists into one row per element with explode
- Quick reference: Pandas cheat sheet
Frequently asked questions
When should I use interpolate() instead of fillna()?
Use interpolate() when the missing values lie between known numeric points and the quantity changes smoothly — temperatures, prices, sensor readings. It estimates the in-between values. Use fillna() (or ffill/bfill) when there is no smooth trend and you simply want to carry the last/next observation forward, or substitute a constant.
What is the difference between method='linear' and method='time'?
method='linear' treats the gaps as evenly spaced regardless of the index, so two missing points always split the difference equally. method='time' (which needs a DatetimeIndex) weights the estimate by the actual elapsed time between known points, so a value three days out is closer to the later reading than one a day out.
Why are leading NaNs still NaN after interpolate()?
By default interpolate only fills gaps that sit between two known values, and it extends forward. A NaN at the very start has no earlier value to interpolate from, so it stays NaN. Pass limit_direction='both' (or 'backward') to also fill leading gaps by extending the first known value backward.
What does the limit parameter control?
limit caps how many consecutive NaNs in a run get filled. With limit=1, only the first missing value next to a known one is filled and the rest of a long gap stays NaN — useful when you trust short gaps but not long stretches of missing data.