How to Replace NaN Values with 0 in a Pandas DataFrame Column

Use the fillna() method on a Series or DataFrame column and pass 0 as the value argument: df['col'] = df['col'].fillna(0) to replace missing values while optionally modifying the data in-place with inplace=True.

Missing data in pandas is represented by NaN (Not-a-Number) markers, and the pandas-dev/pandas repository provides a unified API to handle these values efficiently. The fillna() method serves as the standard mechanism to replace NaN values with scalars such as 0, operating across single columns, entire DataFrames, or specific data blocks internally.

Using fillna() to Replace Missing Values

The fillna() method is the primary interface for replacing NaN values with 0 or any other scalar value. You can apply it to a single column (Series) or the entire DataFrame depending on your data cleaning requirements.

Replace NaN in a Single Column

To replace NaN values with 0 in a specific column, call fillna() on that Series and assign the result back to the column:

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "A": [1, np.nan, 3],
    "B": [4, 5, np.nan]
})

# Replace NaN in column 'A' with 0

df["A"] = df["A"].fillna(0)
print(df)

This operation returns a new Series with NaN values substituted with 0.0, leaving column B unchanged.

Replace NaN Across an Entire DataFrame

To fill all NaN values across every column simultaneously, call fillna() directly on the DataFrame:


# Replace all NaN values in the DataFrame with 0

df_filled = df.fillna(0)
print(df_filled)

This approach applies the fill operation to every block in the underlying data structure, converting all missing values to 0 regardless of their column location.

Limit the Number of Replacements

Use the limit parameter to restrict how many consecutive NaN values are replaced within each column:

df2 = pd.DataFrame({"C": [np.nan, np.nan, 2, np.nan]})

# Only replace the first two NaN values with 0

df2_filled = df2.fillna(0, limit=2)
print(df2_filled)

Internal Implementation of fillna()

According to the pandas source code, the fillna() operation follows a multi-layered architecture that validates arguments, dispatches to generic handlers, and executes optimized block-level replacements.

Argument Validation

When you invoke fillna(), pandas first validates the input arguments through _validate_fillna_kwargs in pandas/util/_validators.py. This helper ensures that the value and method parameters are compatible and correctly formatted before processing begins.

Generic Dispatcher in NDFrame

Both Series and DataFrame inherit from NDFrame, whose fillna implementation resides in pandas/core/generic.py (around line 6923). This method prepares the fill value, processes the limit and inplace flags, and forwards the request to the underlying BlockManager. The generic implementation handles the logic for determining whether to return a new object or modify the existing one based on the inplace parameter.

Block Manager Coordination

The actual data storage in pandas uses a BlockManager, implemented in pandas/core/internals/managers.py. When fillna() is called, the manager iterates over each data block (grouped by dtype) and delegates the filling operation to block-specific methods. This architecture allows pandas to handle heterogeneous data types efficiently without converting the entire dataset to a single dtype.

Block-Level Optimization

Each block type implements its own optimized fillna routine using NumPy or Cython kernels:

These block-level implementations ensure that replacing NaN with 0 occurs with minimal memory overhead and maximum computational speed.

Summary

  • Primary Method: Use df['column'].fillna(0) to replace NaN values with 0 in specific columns, or df.fillna(0) for the entire DataFrame.
  • In-Place Operations: Pass inplace=True to modify the original DataFrame without creating a copy, as handled by the NDFrame.fillna dispatcher in pandas/core/generic.py.
  • Limit Control: Use the limit parameter to restrict how many consecutive NaN values are filled per column.
  • Internal Architecture: The operation flows through pandas/util/_validators.py for argument checking, pandas/core/internals/managers.py for block coordination, and dtype-specific implementations like pandas/core/arrays/masked.py for execution.
  • Testing: The correctness of these operations is verified in pandas/tests/series/methods/test_fillna.py.

Frequently Asked Questions

Does fillna() modify the DataFrame in place?

By default, fillna() returns a new DataFrame or Series and leaves the original unchanged. However, you can modify the original object by setting inplace=True: df['col'].fillna(0, inplace=True). According to the implementation in pandas/core/generic.py, this flag determines whether the method returns a new object or updates the existing block manager data directly.

Can I replace NaN values with different values for different columns?

Yes. Pass a dictionary to fillna() where keys are column names and values are the fill values for those specific columns: df.fillna({'A': 0, 'B': 99}). The NDFrame.fillna method in pandas/core/generic.py handles dictionary inputs by applying the specified fill value to each corresponding column block individually.

What is the difference between fillna(0) and replace(np.nan, 0)?

fillna(0) is specifically designed for missing value imputation and uses optimized internal block manager paths in pandas/core/internals/managers.py. replace(np.nan, 0) is a more general pattern-matching operation that scans for the exact value np.nan and substitutes it, which may be slower and behaves differently with respect to inplace operations and data type conversions.

Does fillna() work with nullable integer dtypes?

Yes. Pandas supports nullable integer types (like Int64 with a capital I) that use a mask to track missing values rather than NaN. When you call fillna(0) on these arrays, the implementation in pandas/core/arrays/masked.py updates the mask and fills the underlying buffer with 0, preserving the integer dtype instead of casting to float as occurs with standard np.nan representations.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s https://instagit.com/install.md

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client