openlang

na.rm = TRUE на группе, где всё NA

Итоги по группам через tapply(x, g, sum, na.rm = TRUE), и одна группа вернулась с 0. Все значения в ней NA. Ни одного измерения, а таблица говорит, что сумма равна нулю.

x <- c(NA_real_, NA_real_)
sum(x, na.rm = TRUE)
#> [1] 0
mean(x, na.rm = TRUE)
#> [1] NaN
max(x, na.rm = TRUE)
#> [1] -Inf
# plus a warning about no non-missing arguments

Каждый ответ по отдельности можно оправдать. Пустая сумма равна 0, пустое среднее - это 0/0. Но рядом в сводной таблице это три разных способа сказать, что ничего не было, и упомянуть об этом удосуживается только max. Хуже всех 0, потому что он похож на измерение.

Версия, которая теперь пойдёт в мои скрипты, возвращает NA, когда складывать нечего.

sum_or_na <- function(x) {
  if (all(is.na(x))) NA_real_ else sum(x, na.rm = TRUE)
}

Мне больше нравится NA, потому что читатель таблицы хотя бы видит, что у группы не было данных.

Разговор продолжается 4

Следуя доводам
  1. Ссылка на ответ

    В этих трёх результатах есть закономерность, которая мне даже нравится. Каждый возвращает нейтральный элемент своей операции. Прибавление 0 ничего не меняет, а -Inf меньше всего на свете, так что с него естественно начинать текущий максимум. По той же причине prod от пустого даёт 1, а min даёт Inf. У среднего нейтрального элемента нет, вот оно и приходит к 0/0. R здесь не небрежен, а верен алгебре, и это другой вопрос, чем то, место ли сумме группы 0 в таблице. Попробуйте prod(x, na.rm = TRUE) на группе из одних NA и посмотрите, раздражает ли 1 так же, как 0.

  2. Ссылка на ответ

    О, это знакомо. У вас везде tapply, или где-то есть и aggregate? У формульного метода aggregate по умолчанию na.action = na.omit, так что строки с NA в отклике удаляются ещё до того, как их увидит ваша функция. Группа, где всё NA, там не возвращается с 0. Её просто нет в результате. Я заметила это только потому, что число групп уменьшилось на одну. Успеет ли sum_or_na вообще вернуть свой NA, если строк уже нет?

  3. Ссылка на ответ

    Последовательно, да, но это последовательность свёртки, а не таблицы. Сумма по пустому и сумма по настоящим значениям приходят одним числом, и вызывающий код их не различит. Исправить можно двумя способами. Вернуть NA, и тогда каждый вызывающий обязан обработать пустой случай или передать его дальше. Или вернуть итог вместе с числом значений, которые в него вошли, и тогда 0 остаётся честным, потому что рядом стоит счётчик 0. Первый способ дешевле для сводной таблицы. Второй стоит лишнего столбца и окупается, когда кто-то захочет взвешивать группы по объёму данных.

  4. Ссылка на ответ

    Оказалось, и то и другое. Скрипт, выдавший 0, использовал tapply. Старый скрипт в той же папке использовал aggregate с формулой, и групп в его выводе было на одну меньше, что списывалось на какой-то фильтр. Это был na.omit. После замены обоих на tapply(x, g, sum_or_na), который сохраняет все уровни g, выводы совпали. Там, где был 0, теперь NA, и пропавшая группа тоже вернулась, тоже с NA. Два разных неправильных ответа из одних и тех же данных. Отныне в третьем столбце стоит число NA по каждой группе.

Другие стороны того же вопроса

  1. sum(X) на матрице из одной строки

    Функция берёт матрицу наблюдений, строки - наблюдения, столбцы - признаки, и нормирует каждый столбец через X ./ sum(X). Долг…

    Ответы 6matlab
  2. Цикл, который выделял память на каждый столбец

    Срезы в Julia копируют. Это известно, но внутри цикла вылетело из головы. Возьмём функцию, которая идёт по столбцам матрицы и…

    Ответы 4julia
  3. f2py копирует мой C-массив при каждом вызове

    Передаю массив NumPy в подпрограмму на Фортране через f2py. Массив создан как обычно, np.zeros((n, m)), то есть в C-порядке.…

    Ответы 3fortran