← Назад к вопросам

Что такое NaN и чем он отличается от None в Python?

1.0 Junior🔥 191 комментариев
#Pandas и обработка данных#Python и программирование

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое NaN и чем он отличается от None в Python?

Для Data Analyst работа с пропущенными и некорректными значениями — повседневная задача. NaN (Not a Number) и None — два разных способа представления отсутствующих или некорректных данных в Python и pandas. Они имеют разные происхождение, поведение и применение.

None — значение отсутствия:

None — это встроенный объект Python, который обозначает отсутствие значения. Это синглтон (единственный объект), используется для обозначения пустого или неопределённого значения.

# None как пустое значение
value = None
print(value)  # None
print(type(value))  # <class 'NoneType'>

# Проверка None
if value is None:
    print("Значение пусто")

# None в списках
data = [1, 2, None, 4]
print(data)  # [1, 2, None, 4]

NaN — математическое отсутствие:

NaN (Not a Number) — это значение стандарта IEEE 754 для чисел с плавающей запятой, обозначающее неопределённый или некорректный результат математической операции.

import math
import numpy as np

# NaN из math модуля
nan_value = float('nan')
print(nan_value)  # nan
print(type(nan_value))  # <class 'float'>

# NaN из numpy
nan_np = np.nan
print(nan_np)  # nan
print(type(nan_np))  # <class 'float'>

# Результат неопределённой операции
result = 0.0 / 0.0  # ZeroDivisionError или inf
result = math.sqrt(-1)  # Ошибка
result = float('inf') - float('inf')  # nan

Ключевые различия:

1. Тип данных

# None — это NoneType
none_val = None
print(type(none_val))  # <class 'NoneType'>

# NaN — это float
nan_val = float('nan')
print(type(nan_val))  # <class 'float'>

2. Сравнение

Это самое важное различие для аналитики:

# None можно сравнивать с is/is not
val = None
print(val is None)      # True
print(val == None)      # True

# NaN НЕ равен даже себе!
nan = float('nan')
print(nan == nan)       # False (!)
print(nan is nan)       # True
print(math.isnan(nan))  # True  <- правильный способ

Это критичное отличие при работе с данными:

# Фильтрация None работает
data = [1, None, 3, None, 5]
result = [x for x in data if x is not None]
print(result)  # [1, 3, 5]

# Фильтрация NaN требует специального подхода
data = [1.0, float('nan'), 3.0, float('nan'), 5.0]
result = [x for x in data if not math.isnan(x)]  # Неправильно!
result = [x for x in data if math.isnan(x) is False]  # Лучше

3. Арифметические операции

# None в арифметике вызывает ошибку
result = None + 5  # TypeError: unsupported operand type(s)

# NaN в арифметике даёт NaN
result = float('nan') + 5  # nan
result = float('nan') * 0  # nan
result = float('nan') / 2  # nan

Работа с pandas:

В pandas оба значения используются, но с нюансами:

import pandas as pd
import numpy as np

# DataFrame с None и NaN
df = pd.DataFrame({
    'col1': [1, None, 3],       # None
    'col2': [1.0, np.nan, 3.0]  # NaN
})

print(df)
#   col1  col2
# 0  1.0   1.0
# 1  NaN   NaN
# 2  3.0   3.0

# pandas преобразует None в NaN для числовых столбцов
print(df.dtypes)
# col1    float64  (None -> NaN)
# col2    float64  (np.nan)

Проверка на пропущенные значения:

df = pd.DataFrame({'A': [1, None, 3], 'B': [1.0, np.nan, 3.0]})

# pd.isna() работает для обоих
print(pd.isna(df['A']))
# 0    False
# 1     True   <- None обнаружен
# 2    False

print(pd.isna(df['B']))
# 0    False
# 1     True   <- NaN обнаружен
# 2    False

# pd.notna() — обратное
print(pd.notna(df))

Заполнение пропущенных значений:

df = pd.DataFrame({'A': [1, None, 3, None], 'B': [1.0, np.nan, 3.0, np.nan]})

# Заполнить одним значением
df_filled = df.fillna(0)
print(df_filled)
#    A    B
# 0  1.0  1.0
# 1  0.0  0.0
# 2  3.0  3.0
# 3  0.0  0.0

# Заполнить методом forward fill
df_ffill = df.fillna(method='ffill')

# Заполнить методом backward fill
df_bfill = df.fillna(method='bfill')

# Интерполяция
df_interp = df.interpolate()

Удаление пропущенных значений:

df = pd.DataFrame({'A': [1, None, 3], 'B': [1.0, np.nan, 3.0]})

# Удалить строки с пропусками
df_clean = df.dropna()
print(df_clean)
#    A    B
# 0  1.0  1.0
# 2  3.0  3.0

# Удалить столбцы с пропусками
df_clean = df.dropna(axis=1)

# Удалить строки, если пропуск в конкретном столбце
df_clean = df.dropna(subset=['A'])

Практический пример аналитики:

import pandas as pd
import numpy as np

# Загрузить данные о продажах
df = pd.read_csv('sales.csv')

# Проверить пропуски
print(df.isnull().sum())  # Количество пропусков в каждом столбце
print(df.isnull().sum().sum())  # Всего пропусков

# Процент пропусков
print((df.isnull().sum() / len(df) * 100).round(2))

# Статистика с пропусками (pandas пропускает NaN)
print(df['amount'].mean())  # Автоматически пропускает NaN
print(df['amount'].sum())   # Автоматически пропускает NaN

# Корреляция (пропускает NaN)
print(df.corr())  # Пропускает NaN автоматически

Когда что использовать:

СитуацияИспользовать
Отсутствие данных в Python кодеNone
Пропущенное числовое значениеNaN (numpy/pandas)
Проверка в условииis None для None, pd.isna() для NaN
Значение в DataFrameNaN (автоматическое преобразование)
Явное обозначение пропускаnp.nan или float('nan')

Выводы:

  1. None — Python синглтон для обозначения отсутствия
  2. NaN — IEEE 754 значение для некорректных чисел
  3. NaN != NaN — главная особенность NaN
  4. В pandas оба преобразуются в NaN для числовых колонок
  5. Используй pd.isna() и pd.notna() для универсальной проверки

Для Data Analyst важно понимать эти различия, чтобы правильно обрабатывать пропущенные данные и избежать ошибок в анализе.

Что такое NaN и чем он отличается от None в Python? | PrepBro