Skip to content

How to Check for NaN Values in Python

Learn how to properly detect NaN (Not a Number) values in Python using math.isnan(), NumPy's np.isnan(), and Pandas' isna() methods, including handling edge cases and performance considerations.

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')

print(val == val)           # False
print(val == float('nan'))  # False

Using Standard Python (math.isnan)

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

import math

val = float('nan')

if val == float('nan'):
    print("This never prints!")

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

s = pd.Series([1, np.nan, None, 4])

print(s.isna())

Output:

0    False
1     True
2     True
3    False
dtype: bool

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]
})

print(df.isna().sum())

rows_with_nan = df[df.isna().any(axis=1)]
print(rows_with_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])

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

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

if np.isnan(arr).all():
    print("Array is completely empty!")

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])

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

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

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]

print(sorted(data))  # [1, 2, 3, nan, nan]

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
Navigation