Skip to main content

How to Check for NaN Values in Python

Handling NaN (Not a Number) is a daily task for Python developers working with data. Because NaN is designed to fail standard equality checks (NaN != NaN), using if x == NaN will never work.

This guide explains how to correctly identify NaN values in standard Python, NumPy, and Pandas.

Why NaN Breaks Equality Checks

Before diving into solutions, understanding why standard comparisons fail is essential.

val = float('nan')

# This is ALWAYS False, even comparing NaN to itself
print(val == val) # False
print(val == float('nan')) # False
IEEE 754 Standard

NaN follows the IEEE 754 floating-point specification, which defines that NaN is not equal to any value, including itself. This behavior is intentional and consistent across programming languages.

Using Standard Python (math.isnan)

For single float values, the built-in math library provides the correct approach.

import math

val = float('nan')

# ⛔️ WRONG: This condition is never True
if val == float('nan'):
print("This never prints!")

# ✅ CORRECT: Use math.isnan()
if math.isnan(val):
print("Value is NaN")

Output:

Value is NaN

Validating User Input

A common use case is sanitizing data before calculations:

import math

def safe_divide(a, b):
result = a / b if b != 0 else float('nan')

if math.isnan(result):
return "Cannot compute"
return result

print(safe_divide(10, 0)) # Cannot compute
print(safe_divide(10, 2)) # 5.0

Output:

Cannot compute
5.0

Using Pandas (DataFrames & Series)

In data science workflows, Pandas provides isna() (or its alias isnull()), which handles both None and NaN and works on entire DataFrames.

import pandas as pd
import numpy as np

# Create Series with missing data
s = pd.Series([1, np.nan, None, 4])

# Check entire series
print(s.isna())

Output:

0    False
1 True
2 True
3 False
dtype: bool
note

Pandas treats None as NaN in numeric columns. Both are considered "missing data" and handled identically by isna().

Filtering and Counting NaN Values

import pandas as pd
import numpy as np

df = pd.DataFrame({
'name': ['Alice', 'Bob', None],
'score': [85, np.nan, 92]
})

# Count NaN per column
print(df.isna().sum())
# Output:
# name 1
# score 1

# Get rows with any NaN
rows_with_nan = df[df.isna().any(axis=1)]
print(rows_with_nan)

# Get rows without NaN
clean_rows = df.dropna()
print(clean_rows)

Output:

name     1
score 1
dtype: int64
name score
1 Bob NaN
2 None 92.0
name score
0 Alice 85.0

Using NumPy (Arrays)

NumPy provides vectorized functions optimized for performance on large arrays.

import numpy as np

arr = np.array([1.5, np.nan, 2.5, np.nan])

# Get boolean mask
mask = np.isnan(arr)
print(mask) # [False True False True]

# Check if ANY NaN exists
if np.isnan(arr).any():
print("Array contains NaN values!")

# Check if ALL values are NaN
if np.isnan(arr).all():
print("Array is completely empty!")

# Count NaN values
nan_count = np.isnan(arr).sum()
print(f"Found {nan_count} NaN values") # Found 2 NaN values

Output:

[False  True False  True]
Array contains NaN values!
Found 2 NaN values

Replacing NaN Values

import numpy as np

arr = np.array([1.0, np.nan, 3.0, np.nan, 5.0])

# Replace NaN with zero
clean_arr = np.nan_to_num(arr, nan=0.0)
print(clean_arr) # [1. 0. 3. 0. 5.]

# Replace NaN with mean of valid values
mean_val = np.nanmean(arr) # Ignores NaN when computing mean
arr[np.isnan(arr)] = mean_val
print(arr) # [1. 3. 3. 3. 5.]

Output:

[1. 0. 3. 0. 5.]
[1. 3. 3. 3. 5.]

The Equality Trick (No Imports)

When imports are not available, you can exploit the IEEE 754 property that NaN is not equal to itself.

def is_nan(x):
return x != x

print(is_nan(float('nan'))) # True
print(is_nan(42)) # False
print(is_nan(None)) # False (be careful!)

Output:

True
False
False
caution

This trick only works for float NaN values. It returns False for None, strings, and other types. Use math.isnan() for clarity and reliability.

Handling NaN in Comparisons

NaN values can cause unexpected behavior in sorting and comparisons:

import numpy as np

data = [3, np.nan, 1, np.nan, 2]

# Standard sort puts NaN at the end
print(sorted(data)) # [1, 2, 3, nan, nan]

# Comparison with NaN is always False
print(np.nan > 5) # False
print(np.nan < 5) # False
print(np.nan == 5) # False

Output:

[3, nan, 1, nan, 2]
False
False
False

Summary

ContextFunctionNotes
Single valuemath.isnan(x)Standard library, no dependencies
NumPy arraynp.isnan(arr)Vectorized, high performance
Pandasdf.isna()Handles None and NaN together
No importsx != xWorks but less readable
Best Practice

Use math.isnan() for individual variable validation. Switch to df.isna() or np.isnan() when working with datasets to leverage vectorized operations and consistent missing-data handling.