Елегантний спосіб повідомляти про відсутні значення в 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символи, і вам доведеться проаналізувати кількість НС.
Джошуа Ульріх,

Я повертаю ваше запитання, оскільки ви опублікували відповідь. Якщо ви хочете прокоментувати відповідь, будь ласка, зробіть це як коментар до цієї відповіді. Якщо питання також містять відповіді, це стає дуже заплутаним.
Андрі

@Andrie: Я не згоден з вашим редагуванням, оскільки ключовою проблемою, з якою я стикаюся, є повідомлення лише про змінні з відсутніми значеннями. Крім того, ваш відкат видалив зміну коду, яку я вніс. Я відредагував своє запитання, щоб включити цю інформацію, і додав до коментаря свою змінену версію коду Джоша.
Зак

@Zach Ваша нова редагування здається мені чудовою. Я не проти додати додаткові дані / запити до питання, коли воно з’являється, до речі, якщо це уточнює питання.
Андрі

Існує півмільйона способів це зробити, див. CRAN Task View - 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

Привіт @ Джошуа Ульріх, дякую за ваш стислий код. Я хотів би додати стовпець у фреймі даних, який відображав би відсоток значень na. Чи можете ви надати допомогу щодо цього?
DukeLover

2
@Zach Я використовую версію вашої пропозиції для перевірки того, чи обов’язкові поля мають значення:M <- colSums(is.na(airquality)); M[M <= 0]
Anthony Simon Mielniczuk

@Joshua, додавши опцію для% s, теж буде тузом!
radek

8

Ми можемо використовувати 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

1
Що перевагу map_dfнад sapply?
Зак

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_dfнад 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 повідомляти, в яких конкретних спостереженнях відсутні дані?
Ентоні Саймон Мельнічук,

не думаю так .. але ви можете отримати це досить просто (вам довелося б замінити якість на власний фрейм даних): 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пакету:

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

Документи також вказують на той факт, що ви можете зберегти ці результати для додаткового аналізу за допомогою missing_data <- plot_missing(data).


plot_missing()Функція в DataExplorerпакеті тепер PlotMissing().
копія

1
@coip PlotMissing()застарілий. Будь ласка, використовуйте plot_missing()замість цього. Детальніше див. №49 .
Боксуан

2

Ще однією функцією, яка допомогла б вам розглянути відсутні дані, буде df_status із бібліотеки funModeling

library(funModeling)

iris.2 - це набір даних iris з деякими доданими 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))})

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. Ви також можете порахувати кількість елементів TRUE в логічному векторі, підсумувавши його.
Houshalter


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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.