Пропущенные значения NA

Разбираемся с пропусками данных — значением NA — и учимся корректно считать статистики при их наличии.

NA (Not Available) — специальное значение, означающее «данные отсутствуют».

Реальные данные почти всегда неполные: кто-то не указал возраст, датчик сломался, ячейка пустая. R помечает такие дыры значением NA. Игнорировать их нельзя — иначе вычисления дадут неверный или «пустой» результат. Пропуски — одна из самых частых причин загадочных багов в анализе: код вроде бы правильный, а среднее внезапно равно NA. R здесь ведёт себя честно и осторожно: он не выдумывает значения за вас, а явно сигнализирует, что результат под вопросом. Научиться замечать и грамотно обрабатывать NA — обязательный навык любого, кто работает с настоящими данными.

NA заразен

Любая арифметика с NA даёт NA — ведь неизвестно, что прибавлять. Это видно при попытке посчитать среднее:

ages <- c(25, NA, 30, 41)
mean(ages)

Вывод:

[1] NA

Один пропуск «отравил» весь результат. R не угадывает за вас — он честно сообщает, что точное среднее посчитать нельзя.

Аргумент na.rm

Чтобы посчитать статистику по имеющимся данным, многим функциям передают na.rm = TRUE — «удали NA перед расчётом»:

ages <- c(25, NA, 30, 41)
mean(ages, na.rm = TRUE)
sum(ages, na.rm = TRUE)

Вывод:

[1] 32
[1] 96

Теперь R посчитал среднее по трём известным значениям: (25 + 30 + 41) / 3 = 32.

Поиск пропусков

Найти, где именно дыры, помогает is.na — она возвращает логический вектор:

ages <- c(25, NA, 30, NA)
is.na(ages)
sum(is.na(ages))

Вывод:

[1] FALSE  TRUE FALSE  TRUE
[1] 2

Приём sum(is.na(x)) — стандартный способ сосчитать количество пропусков: логические TRUE превращаются в 1.

Как работает под капотом

Нельзя сравнивать с NA обычным ==: выражение x == NA вернёт не TRUE, а снова NA — ведь неизвестное не равно и не не равно ничему. Именно поэтому существует отдельная функция is.na. Это частая ловушка: новички пишут x[x == NA] и получают пустоту вместо пропусков; правильно — x[is.na(x)].

Частые ошибки

  • Забыть na.rm = TRUE. Тогда mean, sum, sd вернут NA при наличии хоть одного пропуска.
  • Сравнивать с NA через ==. Используйте только is.na().
  • Путать NA и NULL. NA — «нет значения в ячейке», NULL — «нет самого объекта». Это разные вещи.

Итог

  • NA — отсутствующее значение, оно «заражает» вычисления.
  • na.rm = TRUE заставляет функцию игнорировать пропуски.
  • is.na(x) находит пропуски, sum(is.na(x)) их считает.
  • Сравнивать с NA через == нельзя — только через is.na.
Проверьте себя
1. Что вернёт mean(c(1, NA, 3)) без дополнительных аргументов?
A[1] 2
B[1] NA
C[1] 4
DОшибку
2. Как заставить mean игнорировать пропуски?
Askip = TRUE
Bna.rm = TRUE
Cignore.na = 1
Ddrop = TRUE
3. Как правильно найти пропуски в векторе x?
Ax == NA
Bis.na(x)
Cx = NA
Dna(x)