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

80

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

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

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

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

Ответы:

156

Просто используйте 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 
Джошуа Ульрих
источник
12
Я немного изменил ваш код, чтобы сообщить только об отсутствующем значении:M <- sapply(airquality, function(x) sum(is.na(x))); M[M>0]
Зак,
Благодаря! Многому научился.
Bombyx mori
Привет, @Joshua Ulrich, большое спасибо за лаконичный код. Я хотел бы добавить столбец во фрейм данных, который бы показывал процент значений na. Не могли бы вы помочь в этом вопросе?
DukeLover
2
@Zach Я использую версию вашего предложения для проверки наличия значений в обязательных полях:M <- colSums(is.na(airquality)); M[M <= 0]
Энтони Саймон Мельничук
@Joshua, добавив опцию для% s, тоже было бы здорово!
radek
8

Мы можем использовать map_dfс purrr.

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
Кейку
источник
1
В чем преимущество map_dfболее sapply?
Zach
1
@Zach Я думаю, что нет большой разницы, но Хэдли сказал не использовать sapply () внутри функции. См. Исключения и отладка · Advanced R. adv-r.had.co.nz/Exceptions-Debugging.html .
Кейку
для ленивых людей вроде меня вы можете написать приведенный выше код в более коротком синтаксисе purrr для функций (~), чтобы он выглядел так:map_df( air quality, ~sum(is.na(.) )
Agile Bean
1
@Zach преимущество map_dfover sapplyтолько тогда, когда результат имеет много строк, поскольку выходной формат map_df всегда является тибблом.
Agile Bean
1
@Zach: лучше использовать vapplyvs sapplyв функциях, потому что vapplyдает вам известную структуру результата (которую вы указываете). sapplyможет возвращать массив или список, в зависимости от вывода функции. Недостатком map_dfявляется то, что вы даете ему data.frame в качестве ввода, и он возвращает подкласс data.frame, а не data.frame. Нет гарантии, что таблицы будут вести себя так же, как data.frames, во всех необходимых случаях в будущем.
Джошуа Ульрих
8

Мой новый фаворит для (не слишком широких) данных - это методы из отличного пакета 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)

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

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

Радек
источник
2
Спасибо, что разместили это! В gg_miss_upset()последней версии теперь есть специальная функция, которая будет передана CRAN, когда они вернутся из отпуска. naniar.njtierney.com/reference/gg_miss_upset.html
Ник Тирни
6
summary(airquality)

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

В VIM пакеты также предлагают некоторые хорошие недостающий участок данных для data.frame

library("VIM")
aggr(airquality)

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

Штеффен Мориц
источник
Может ли пакет VIM сообщить, в каких конкретных наблюдениях отсутствуют данные?
Энтони Саймон Мельничук
не думаю ... но вы можете получить это довольно просто (вам придется заменить airquality своим собственным фреймом данных): res <- airquality [rowSums (is.na (airquality))> 0,]
Штеффен Мориц,
4

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

То есть

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

  2. is.na() правда, если это NA

  3. sum() TRUEесть 1, FALSEесть0

Кит Уиттингем
источник
это не отвечает на исходный вопрос, который состоит в том, чтобы найти количество NAs для всех столбцов в данных
Бен Болкер
4

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

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

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

Радек
источник
plot_missing()Функция в DataExplorerпакете теперь PlotMissing().
coip 06
1
@coip PlotMissing()устарел. Пожалуйста, используйте plot_missing()вместо этого. См. # 49 для более подробной информации.
Boxuan 02
2

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

library(funModeling)

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

df_status(iris.2)

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

Шахан Дегамвала
источник
1

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

library(visdat)
vis_miss(airquality)

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

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

Радек
источник
1

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

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

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

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

row.has.na <- apply(training, 1, function(x){any(is.na(x))})
drexxx
источник
1

Другой графический и интерактивный способ - использовать 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"))

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

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

Радек
источник
0

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

length(which(is.na(airquality[1])==T))
Чинтак Чапиа
источник
4
Вам не нужно сравнивать логический вектор с T. Вы также можете подсчитать количество ИСТИННЫХ элементов в логическом векторе, суммируя его.
Houshalter 01
0

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
сбха
источник