Элегантный способ сообщить об отсутствующих значениях в data.frame

Вот небольшой фрагмент кода, который я написал для сообщения о переменных с отсутствующими значениями из фрейма данных. Я пытаюсь придумать более элегантный способ сделать это, который, возможно, возвращает data.frame, но я застрял:

for (Var in names(airquality)) {
    missing <- sum(is.na(airquality[,Var]))
    if (missing > 0) {
        print(c(Var,missing))
    }
}

Изменить: я имею дело с data.frames с десятками или сотнями переменных, поэтому важно, чтобы мы сообщали только о переменных с отсутствующими значениями.


person Zach    schedule 29.11.2011    source источник
comment
@kohske: это была моя первая мысль, но результат - table символов, и вам нужно будет проанализировать количество NA.   -  person Joshua Ulrich    schedule 30.11.2011
comment
Я возвращаюсь к вашему вопросу, поскольку вы отправили ответ. Если вы хотите прокомментировать ответ, сделайте это как комментарий к этому ответу. Если вопросы также содержат ответы, это становится очень запутанным.   -  person Andrie    schedule 30.11.2011
comment
@Andrie: Я не согласен с вашим изменением, поскольку ключевая проблема, с которой я столкнулся, - это сообщение только о переменных с пропущенными значениями. Кроме того, ваш откат удалил изменение, которое я внес в код. Я отредактировал свой вопрос, чтобы включить эту информацию, и добавил мою измененную версию кода Джоша в комментарий.   -  person Zach    schedule 30.11.2011
comment
@Zach Мне нравится твоя новая редакция. Я не прочь добавить дополнительные данные / запросы в вопрос, когда он появится, кстати, если это проясняет вопрос.   -  person Andrie    schedule 30.11.2011
comment
Есть полмиллиона способов сделать это, см. Представление задач CRAN - MissingData   -  person zx8754    schedule 20.05.2019


Ответы (13)


Просто используйте sapply

> sapply(airquality, function(x) sum(is.na(x)))
  Ozone Solar.R    Wind    Temp   Month     Day 
     37       7       0       0       0       0

Вы также можете использовать apply или colSums в матрице, созданной is.na()

> apply(is.na(airquality),2,sum)
  Ozone Solar.R    Wind    Temp   Month     Day 
     37       7       0       0       0       0
> colSums(is.na(airquality))
  Ozone Solar.R    Wind    Temp   Month     Day 
     37       7       0       0       0       0 
person Joshua Ulrich    schedule 29.11.2011
comment
Я немного изменил ваш код, чтобы сообщить только об отсутствующем значении: M <- sapply(airquality, function(x) sum(is.na(x))); M[M>0] - person Zach; 30.11.2011
comment
Спасибо! Многому научился. - person Bombyx mori; 15.11.2015
comment
Привет, @Joshua Ulrich, большое спасибо за лаконичный код. Я хотел бы добавить столбец во фрейм данных, который бы показывал процент значений na. Не могли бы вы помочь в этом вопросе? - person DukeLover; 17.06.2017
comment
@Zach Я использую версию вашего предложения для проверки того, что обязательные поля имеют значение: M <- colSums(is.na(airquality)); M[M <= 0] - person Anthony Simon Mielniczuk; 03.10.2017
comment
@ Джошуа, добавив опцию для% s, тоже было бы здорово! - person radek; 30.05.2019

Мой новый фаворит для (не слишком широких) данных - это методы из отличного пакета naniar. Вы получаете не только частоты, но и схемы отсутствия:

library(naniar)
library(UpSetR)

riskfactors %>%
  as_shadow_upset() %>%
  upset()

введите описание изображения здесь

Часто бывает полезно увидеть, где пропущены по отношению к отсутствию, что может быть достигнуто путем построения графика рассеяния с пропусками:

ggplot(airquality,
       aes(x = Ozone,
           y = Solar.R)) +
 geom_miss_point()

введите описание изображения здесь

Или для категориальных переменных:

gg_miss_fct(x = riskfactors, fct = marital)

введите описание изображения здесь

Эти примеры взяты из пакета vignette, в котором перечислены другие интересные визуализации.

person radek    schedule 02.07.2018
comment
Спасибо, что разместили это! В последней версии теперь есть специальная gg_miss_upset() функция, которая будет отправлена ​​в CRAN, когда они вернутся из отпуска. naniar.njtierney.com/reference/gg_miss_upset.html - person Nick Tierney; 10.09.2018

Мы можем использовать map_df с мурлыканьем.

library(mice)
library(purrr)

# map_df with purrr
map_df(airquality, function(x) sum(is.na(x)))
# A tibble: 1 × 6
# Ozone Solar.R  Wind  Temp Month   Day
# <int>   <int> <int> <int> <int> <int>
# 1    37       7     0     0     0     0
person Keiku    schedule 27.01.2017
comment
В чем преимущество map_df перед sapply? - person Zach; 27.01.2017
comment
@Zach Я думаю, что нет большой разницы, но Хэдли сказал не использовать sapply () внутри функции. См. Исключения и отладка. · Advanced R. adv-r.had.co.nz/ Исключения-Debugging.html. - person Keiku; 27.01.2017
comment
для ленивых людей вроде меня вы можете написать приведенный выше код в более коротком синтаксисе purrr для функций (~), чтобы он выглядел так: map_df( air quality, ~sum(is.na(.) ) - person Agile Bean; 29.01.2019
comment
@Zach Преимущество map_df перед sapply только тогда, когда результат имеет много строк, поскольку выходной формат map_df всегда является тибблом. - person Agile Bean; 29.01.2019
comment
@Zach: лучше использовать vapply vs sapply в функциях, потому что vapply дает вам известную структуру результата (которую вы указываете). sapply может возвращать массив или список, в зависимости от вывода функции. Недостатком map_df является то, что вы даете ему data.frame в качестве ввода, и он возвращает подкласс data.frame, а не data.frame. Нет гарантии, что таблицы будут вести себя так же, как data.frames, во всех необходимых случаях в будущем. - person Joshua Ulrich; 30.05.2019

summary(airquality)

уже дает вам эту информацию

Пакеты VIM также предлагают несколько хороших графиков отсутствующих данных для data.frame.

library("VIM")
aggr(airquality)

введите здесь описание изображения

person Steffen Moritz    schedule 10.11.2016
comment
Может ли пакет VIM сообщить, по каким конкретным наблюдениям отсутствуют данные? - person Anthony Simon Mielniczuk; 17.11.2016
comment
не думаю ... но вы можете получить это довольно легко (вам придется заменить airquality вашим собственным фреймом данных): res ‹- airquality [rowSums (is.na (airquality))› 0,] - person Steffen Moritz; 18.11.2016

Более лаконично: sum(is.na(x[1]))

То есть

  1. x[1] Посмотрите на первый столбец

  2. is.na() верно, если NA

  3. sum() TRUE is 1, FALSE is 0

person Keith Whittingham    schedule 11.04.2015
comment
это не отвечает на исходный вопрос, который заключается в том, чтобы найти количество NA для всех столбцов в данных - person Ben Bolker; 11.04.2015

Еще одна графическая альтернатива - функция plot_missing из отличного пакета DataExplorer:

введите здесь описание изображения

Docs также указывает на то, что вы можете сохранить эти результаты для дополнительного анализа с помощью missing_data <- plot_missing(data).

person radek    schedule 13.02.2018
comment
Функция plot_missing() в пакете DataExplorer теперь PlotMissing(). - person coip; 07.03.2018
comment
@coip PlotMissing() устарел. Вместо этого используйте plot_missing(). Дополнительные сведения см. В # 49. - person Boxuan; 02.08.2018

Еще одна функция, которая поможет вам увидеть недостающие данные, - это df_status из библиотеки funModeling.

library(funModeling)

iris.2 - это набор данных радужной оболочки с некоторыми добавленными NA. Вы можете заменить его своим набором данных.

df_status(iris.2)

Это даст вам количество и процентное соотношение НП в каждом столбце.

person Shahan Degamwala    schedule 06.02.2017

Еще одно графическое решение - visdat пакет предлагает vis_miss.

library(visdat)
vis_miss(airquality)

введите здесь описание изображения

Очень похоже на вывод Amelia с небольшой разницей в выдаче% s при отсутствии из коробки.

person radek    schedule 03.12.2017

Я думаю, что библиотека Amelia отлично справляется с обработкой недостающих данных, а также включает карту для визуализации недостающих строк.

install.packages("Amelia")
library(Amelia)
missmap(airquality)

введите здесь описание изображения

Вы также можете запустить следующий код, который вернет логические значения na

row.has.na <- apply(training, 1, function(x){any(is.na(x))})
person drexxx    schedule 19.04.2017

Другой графический и интерактивный способ - использовать функцию is.na10 из библиотеки heatmaply:

library(heatmaply)

heatmaply(is.na10(airquality), grid_gap = 1, 
          showticklabels = c(T,F),
            k_col =3, k_row = 3,
            margins = c(55, 30), 
            colors = c("grey80", "grey20"))

введите здесь описание изображения

Вероятно, не будет работать с большими наборами данных.

person radek    schedule 27.08.2018

Если вы хотите сделать это для определенного столбца, вы также можете использовать этот

length(which(is.na(airquality[1])==T))
person Chintak Chhapia    schedule 09.06.2014
comment
Вам не нужно сравнивать логический вектор с T. Вы также можете подсчитать количество ИСТИННЫХ элементов в логическом векторе, суммируя его. - person Houshalter; 01.12.2014

Функцию пакета ExPanDaR prepare_missing_values_graph можно использовать для исследования данных панели:

введите здесь описание изображения

person radek    schedule 05.04.2019

dplyr решением для подсчета может быть:

summarise_all(df, ~sum(is.na(.)))

Или получить процент:

summarise_all(df, ~(sum(is_missing(.) / nrow(df))))

Возможно, также стоит отметить, что отсутствующие данные могут быть некрасивыми, непоследовательными и не всегда кодироваться как NA в зависимости от источника или того, как они обрабатываются при импорте. Следующая функция может быть изменена в зависимости от ваших данных и того, что вы хотите считать пропущенным:

is_missing <- function(x){
  missing_strs <- c('', 'null', 'na', 'nan', 'inf', '-inf', '-9', 'unknown', 'missing')
  ifelse((is.na(x) | is.nan(x) | is.infinite(x)), TRUE,
         ifelse(trimws(tolower(x)) %in% missing_strs, TRUE, FALSE))
}

# sample ugly data
df <- data.frame(a = c(NA, '1', '  ', 'missing'),
                 b = c(0, 2, NaN, 4),
                 c = c('NA', 'b', '-9', 'null'),
                 d = 1:4,
                 e = c(1, Inf, -Inf, 0))

# counts:
> summarise_all(df, ~sum(is_missing(.)))
  a b c d e
1 3 1 3 0 2

# percentage:
> summarise_all(df, ~(sum(is_missing(.) / nrow(df))))
     a    b    c d   e
1 0.75 0.25 0.75 0 0.5
person sbha    schedule 14.03.2020