Что такое NaN и чем он отличается от None в Python?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое 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 |
| Значение в DataFrame | NaN (автоматическое преобразование) |
| Явное обозначение пропуска | np.nan или float('nan') |
Выводы:
- None — Python синглтон для обозначения отсутствия
- NaN — IEEE 754 значение для некорректных чисел
- NaN != NaN — главная особенность NaN
- В pandas оба преобразуются в NaN для числовых колонок
- Используй pd.isna() и pd.notna() для универсальной проверки
Для Data Analyst важно понимать эти различия, чтобы правильно обрабатывать пропущенные данные и избежать ошибок в анализе.