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

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, 5
import 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: float64

2 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: float64

3 Limits, Direction, and vs ffill / bfill

Two controls keep interpolation honest, and one comparison keeps it in context:

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 gap
import 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: float64
import 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.

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

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.