Handling NaN & Infinity

Reviewed & published by Brayan K

NaN ("Not a Number") and infinity are special floating-point values NumPy uses to represent missing or undefined data, and learning to detect and clean them is essential for trustworthy numeric results.

Part of the free NumPy course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

You'll discover why NaN never equals itself, detect it with np.isnan and friends, compute around it using nan-aware reductions, and replace it with np.nan_to_num.

What You'll Learn in This Lesson

1 Meet np.nan and np.inf

np.nan is a special float meaning "missing or undefined", and np.inf represents infinity (often from dividing by zero). The surprising part: NaN never equals anything, not even itself, so np.nan == np.nan is False. That single fact is why you cannot find NaN with ==.

import numpy as np

np.nan == np.nan      # False  (!)
np.nan != np.nan      # True
np.inf > 1e300        # True
-np.inf < -1e300      # True

# Any arithmetic with NaN produces NaN
np.nan + 5            # nan
import numpy as np

print(np.nan == np.nan)        # False
print(np.nan != np.nan)        # True
print(np.nan + 100)            # nan

# inf behaves like a real infinity
print(np.inf > 10 ** 300)      # True
print(1 / np.inf)              # 0.0

# ✅ Expected output:
# False
# True
# nan
# True
# 0.0

2 Detecting Values: isnan, isinf, isfinite

Three element-wise helpers give you boolean masks. np.isnan flags NaN, np.isinf flags positive or negative infinity, and np.isfinite flags the "good" values that are neither. Combine them with boolean indexing to count or filter.

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

np.isnan(arr)      # [False  True False False False]
np.isinf(arr)      # [False False False  True False]
np.isfinite(arr)   # [ True False  True False  True]

# Keep only the finite values
arr[np.isfinite(arr)]    # [1. 3. 5.]
import numpy as np

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

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

# Count the missing values
print(np.isnan(arr).sum())     # 1

# Filter to finite values only
print(arr[np.isfinite(arr)])   # [1. 3. 5.]

# ✅ Expected output:
# [False  True False False False]
# [ True False  True False  True]
# 1
# [1. 3. 5.]

3 nan-Aware Reductions & Replacement

Ordinary sum and mean propagate NaN — one missing value poisons the whole result. The fix is the nan* family: np.nansum, np.nanmean, np.nanmax, and friends simply skip NaN. To replace the bad values entirely, np.nan_to_num swaps NaN for 0 and infinities for large finite numbers.

arr = np.array([1.0, 2.0, np.nan, 4.0])

arr.sum()           # nan   -> poisoned
np.nansum(arr)      # 7.0   -> skips NaN
np.nanmean(arr)     # 2.3333 (mean of 1, 2, 4)

# Replace special values with finite numbers
np.nan_to_num(arr)                 # [1. 2. 0. 4.]
np.nan_to_num(arr, nan=-1.0)       # [ 1.  2. -1.  4.]
import numpy as np

arr = np.array([1.0, 2.0, np.nan, 4.0])

# Regular reduction is poisoned by NaN
print(arr.sum())               # nan

# nan-aware versions skip the missing value
print(np.nansum(arr))          # 7.0
print(round(np.nanmean(arr), 4))   # 2.3333

# Replace NaN with 0 (default) or a custom value
print(np.nan_to_num(arr))          # [1. 2. 0. 4.]
print(np.nan_to_num(arr, nan=-1))  # [ 1.  2. -1.  4.]

# ✅ Expected output:
# nan
# 7.0
# 2.3333
# [1. 2. 0. 4.]
# [ 1.  2. -1.  4.]

🎯 YOUR TURN: Fill in the Blank

Replace ___ with the function that computes a mean while ignoring the missing value.

import numpy as np

readings = np.array([10.0, np.nan, 20.0, 30.0])

# 🎯 YOUR TURN:
# Compute the average of the real readings, ignoring NaN.
# Hint: it is the nan-aware version of mean.
avg = np.___(readings)

print(avg)
# Expected output:
# 20.0

Answer: nanmean — it averages 10, 20, 30 (skipping NaN) to get 20.0.

! Common Errors (And How to Fix Them)

❌ Testing for NaN with ==

arr[arr == np.nan]    # ❌ always empty, finds nothing

✅ Fix: use the dedicated mask arr[np.isnan(arr)].

❌ Surprised that sum/mean returned nan

np.array([1.0, np.nan, 3.0]).mean()   # nan

✅ Fix: use the nan-aware reduction np.nanmean(arr) to skip NaN.

❌ NaN inside an integer array

NaN is a float; you cannot store it in an int array.

✅ Fix: create the array as float, e.g. np.array([1, 2], dtype=float), before inserting NaN.

🎯 Mini Challenge: Clean Sensor Data

A sensor stream has a missing reading. Count the missing values, compute the mean of the valid ones, then build a cleaned array where NaN is replaced by that mean.

import numpy as np

data = np.array([4.0, np.nan, 6.0, 8.0, np.nan, 2.0])

# How many are missing?
missing = np.isnan(data).sum()
print("missing:", missing)         # missing: 2

# Mean of the valid readings
valid_mean = np.nanmean(data)
print("mean:", valid_mean)         # mean: 5.0

# Replace NaN with the valid mean
cleaned = np.where(np.isnan(data), valid_mean, data)
print(cleaned)                     # [4. 5. 6. 8. 5. 2.]

# ✅ Expected output:
# missing: 2
# mean: 5.0
# [4. 5. 6. 8. 5. 2.]

❓ Frequently Asked Questions

Lesson complete — missing data, handled!

You know why nan != nan, detect special values with isnan/isinf/isfinite, reduce safely with the nan* family, and clean arrays with np.nan_to_num.

Practice quiz

What does np.nan represent?

  • A missing or undefined value
  • Zero
  • The largest integer
  • An empty string

Answer: A missing or undefined value. np.nan ('Not a Number') marks missing or undefined floating-point data.

What does the comparison np.nan == np.nan evaluate to?

  • True
  • False
  • nan
  • An error

Answer: False. NaN never equals anything, including itself, so the result is False.

Which function flags positive or negative infinity?

  • np.isnan
  • np.isfinite
  • np.isinf
  • np.nan_to_num

Answer: np.isinf. np.isinf returns True wherever a value is positive or negative infinity.

What does np.isfinite([1.0, np.nan, 3.0, np.inf, 5.0]) return?

  • [True False True False True]
  • [True True True True True]
  • [False False False False False]
  • [False True False True False]

Answer: [True False True False True]. isfinite is True only for the non-NaN, non-inf values: positions 0, 2, 4.

What does 1 / np.inf evaluate to?

  • nan
  • inf
  • 1.0
  • 0.0

Answer: 0.0. Dividing a finite number by infinity gives 0.0.

Why does arr[arr == np.nan] find nothing?

  • NaN is never equal to itself, so the mask is all False
  • arr is empty
  • It raises an error
  • == rounds the values

Answer: NaN is never equal to itself, so the mask is all False. Because NaN != NaN, the mask is all False; use np.isnan instead.

What does np.nansum([1.0, 2.0, np.nan, 4.0]) return?

  • nan
  • 7.0
  • 6.0
  • 4.0

Answer: 7.0. nansum skips the NaN and adds 1+2+4 = 7.0.

What does np.nan_to_num([1.0, 2.0, np.nan, 4.0]) return by default?

  • [1. 2. nan 4.]
  • [nan nan nan nan]
  • [1. 2. 0. 4.]
  • [0. 0. 0. 0.]

Answer: [1. 2. 0. 4.]. nan_to_num replaces NaN with 0 by default: [1. 2. 0. 4.].

Why can't you store NaN in an integer array?

  • NaN is a float-only value
  • Integers are read-only
  • NaN is a string
  • Arrays forbid zeros

Answer: NaN is a float-only value. NaN is a floating-point value, so the array must be float dtype to hold it.

Which comparison is True?

  • np.nan == 0
  • np.nan != np.nan is False
  • -np.inf < -1e300
  • 1 / np.inf > 0

Answer: -np.inf < -1e300. Negative infinity is less than any finite number, so -np.inf < -1e300 is True.

Continue this course

Frequently asked questions

Why does np.nan == np.nan return False?

NaN means 'Not a Number', a special floating-point value that represents an undefined or missing result. By the IEEE-754 standard NaN is defined to never equal anything, including itself, so np.nan == np.nan is False. That is exactly why you must test for it with np.isnan() instead of the == operator.

How do I check for NaN or infinity correctly?

Use the dedicated functions: np.isnan(arr) returns a boolean mask of where NaN appears, np.isinf(arr) flags positive or negative infinity, and np.isfinite(arr) marks the 'good' values that are neither NaN nor inf. These work element-wise on whole arrays and are the only reliable way to find these special values.

Why does sum() return nan when my data has a missing value?

Regular reductions like sum and mean propagate NaN: if any element is NaN, the result is NaN, because arithmetic with NaN always yields NaN. To skip the missing values instead, use the nan-aware versions np.nansum, np.nanmean, np.nanmax and so on, which ignore NaN and compute over the remaining numbers.

How do I replace NaN and infinity with real numbers?

np.nan_to_num(arr) replaces NaN with 0, positive infinity with a very large finite number, and negative infinity with a very small one. You can customise the fills, for example np.nan_to_num(arr, nan=0.0, posinf=1e6). It is the quickest way to make an array safe for code that cannot tolerate special values.