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
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
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
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
| Context | Function | Notes |
|---|---|---|
| Single value | math.isnan(x) | Standard library, no dependencies |
| NumPy array | np.isnan(arr) | Vectorized, high performance |
| Pandas | df.isna() | Handles None and NaN together |
| No imports | x != x | Works but less readable |
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.