How to Handle Missing Data in Pandas

โฑ๏ธ 45 sec read ๐Ÿ Python

Handle missing data in pandas in three steps: find it with isna(), then either fill it (fillna, ffill, bfill, interpolate) or drop it (dropna). Which one is right depends on whether a missing value means "zero," "unchanged," or "unusable."

How Do You Find Missing Values?

isna() returns a boolean mask of missing cells, and summing it gives a per-column count โ€” the standard first look at any new dataset. notna() is its inverse.

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "temp":  [20.1, np.nan, 22.4, np.nan, 23.0],
    "city":  ["NYC", "NYC", None, "LA", "LA"],
})

df.isna().sum()
# temp    2
# city    1

How Does fillna Work?

fillna replaces missing values with a constant, and accepts a dict to use a different fill per column โ€” usually better than one blanket value.

df.fillna(0)                     # every NaN becomes 0 (rarely right)

df.fillna({"temp": df["temp"].mean(), "city": "unknown"})
#    temp     city
# 0  20.1      NYC
# 1  21.8      NYC   <- column mean
# 2  22.4  unknown
# 3  21.8       LA
# 4  23.0       LA

What Are ffill, bfill, and interpolate?

ffill() carries the last valid value forward, bfill() pulls the next valid value backward, and interpolate() estimates numeric gaps linearly. These fit ordered data like time series, where "missing" usually means "unchanged since last reading."

df["temp"].ffill()          # 20.1, 20.1, 22.4, 22.4, 23.0
df["temp"].bfill()          # 20.1, 22.4, 22.4, 23.0, 23.0
df["temp"].interpolate()    # 20.1, 21.25, 22.4, 22.7, 23.0

# df.fillna(method="ffill") is deprecated โ€” call ffill() directly.

When Should You Use dropna?

dropna removes rows (or columns with axis=1) containing missing values; use it when a row is unusable without the value, not as a reflex. subset= limits which columns count, and thresh= keeps rows with at least N valid values.

df.dropna()                        # drop rows with ANY NaN
df.dropna(subset=["temp"])         # only require temp to be present
df.dropna(thresh=2)                # keep rows with >= 2 non-null values

Why Avoid inplace=True?

Pandas is moving away from inplace=True: it rarely saves memory, breaks method chaining, and is deprecated for most methods on the path to pandas 3.0. Assign the result instead.

# Aging pattern:
df.fillna(0, inplace=True)

# Preferred:
df = df.fillna(0)
clean = df.dropna(subset=["temp"]).assign(city=lambda d: d["city"].fillna("unknown"))

Common Pitfalls

Missing values often enter at load time โ€” the na_values options covered in reading CSVs in Python let you catch placeholders like "N/A" or "-" as real NaN from the start.

Pro Tip: Before filling anything, check whether missingness carries meaning. df["temp"].isna().groupby(df["city"]).mean() shows if one group is disproportionately missing โ€” often a pipeline bug, not random noise.

โ† Back to Python Tips