Elegante Möglichkeit, fehlende Werte in einem data.frame zu melden

80

Hier ist ein kleiner Code, den ich geschrieben habe, um Variablen mit fehlenden Werten aus einem Datenrahmen zu melden. Ich versuche mir einen eleganteren Weg zu überlegen, der vielleicht einen data.frame zurückgibt, aber ich stecke fest:

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

Bearbeiten: Ich habe es mit data.frames mit Dutzenden bis Hunderten von Variablen zu tun, daher ist es wichtig, dass wir nur Variablen mit fehlenden Werten melden.

Zach
quelle
@kohske: Das war mein erster Gedanke, aber die Ergebnisse sind tableZeichen und Sie müssten die Anzahl der NAs analysieren.
Joshua Ulrich
Ich stelle Ihre Frage zurück, da Sie eine Antwort gepostet haben. Wenn Sie eine Antwort kommentieren möchten, tun Sie dies bitte als Kommentar zu dieser Antwort. Wenn Fragen auch Antworten enthalten, wird dies sehr verwirrend.
Andrie
@Andrie: Ich bin mit Ihrer Bearbeitung nicht einverstanden, da ein Hauptproblem darin besteht, nur Variablen mit fehlenden Werten zu melden. Außerdem hat Ihr Rollback eine Änderung entfernt, die ich am Code vorgenommen habe. Ich habe meine Frage so bearbeitet, dass sie diese Informationen enthält, und meine geänderte Version von Joshs Code zu einem Kommentar hinzugefügt.
Zach
@Zach Deine neue Bearbeitung sieht für mich gut aus. Ich bin übrigens nicht abgeneigt, einer Frage zusätzliche Daten / Anfragen hinzuzufügen, sobald diese aktiv sind, wenn dies die Frage klärt.
Andrie
Es gibt eine halbe Million Möglichkeiten, dies zu tun, siehe CRAN Task View - MissingData
zx8754

Antworten:

155

Benutz einfach sapply

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

Sie können auch applyoder colSumsauf der von erstellten Matrix verwendenis.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 
Joshua Ulrich
quelle
11
Ich habe Ihren Code leicht geändert, um nur den fehlenden Wert zu melden:M <- sapply(airquality, function(x) sum(is.na(x))); M[M>0]
Zach
Vielen Dank! Viel gelernt.
Bombyx Mori
Hallo @Joshua Ulrich, vielen Dank für deinen prägnanten Code. Ich möchte dem Datenrahmen eine Spalte hinzufügen, die den Prozentsatz der na-Werte anzeigt. Können Sie uns hierzu bitte helfen?
DukeLover
2
@ Zach Ich verwende eine Version Ihres Vorschlags, um zu überprüfen, ob die erforderlichen Felder einen Wert haben:M <- colSums(is.na(airquality)); M[M <= 0]
Anthony Simon Mielniczuk
@Joshua Hinzufügen einer Option für% s wäre auch ein Ass!
Radek
8

Wir können map_dfmit purrr verwenden.

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
Keiku
quelle
1
Was ist der Vorteil von map_dfüber sapply?
Zach
1
@Zach Ich denke, dass es keinen großen Unterschied gibt, aber Hadley sagte, dass er sapply () nicht in einer Funktion verwenden soll. Siehe Ausnahmen und Debugging · Advanced R. adv-r.had.co.nz/Exceptions-Debugging.html .
Keiku
Für faule Leute wie mich können Sie den obigen Code in kürzerer Purrr-Syntax für Funktionen (~) schreiben, so dass es so aussieht:map_df( air quality, ~sum(is.na(.) )
Agile Bean
1
@Zach der Vorteil von map_dfover sapplyist nur, wenn das Ergebnis viele Zeilen enthält, da das Ausgabeformat von map_df immer ein tibble ist.
Agile Bean
1
@Zach: Es ist besser, vapplyvs sapplyin Funktionen zu verwenden, da vapplySie eine bekannte Ergebnisstruktur erhalten (die Sie angeben). sapplykann abhängig von der Funktionsausgabe ein Array oder eine Liste zurückgeben. Ein Nachteil von map_dfist, dass Sie ihm einen data.frame als Eingabe geben und eine data.frame-Unterklasse zurückgeben, keinen data.frame. Es gibt keine Garantie dafür, dass sich tibbles in Zukunft in allen erforderlichen Fällen wie data.frames verhalten.
Joshua Ulrich
8

Mein neuer Favorit für (nicht zu breite) Daten sind Methoden aus einem exzellenten Naniar- Paket. Sie erhalten nicht nur Frequenzen, sondern auch Muster des Fehlens:

library(naniar)
library(UpSetR)

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

Geben Sie hier die Bildbeschreibung ein

Es ist oft nützlich zu sehen, wo sich die Fehlschläge in Bezug auf Nicht-Fehlen befinden, was durch Zeichnen eines Streudiagramms mit Fehlschlägen erreicht werden kann:

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

Geben Sie hier die Bildbeschreibung ein

Oder für kategoriale Variablen:

gg_miss_fct(x = riskfactors, fct = marital)

Geben Sie hier die Bildbeschreibung ein

Diese Beispiele stammen aus einer Paketvignette , in der andere interessante Visualisierungen aufgeführt sind.

Radek
quelle
2
Danke, dass du das gepostet hast! gg_miss_upset()In der neuesten Version gibt es jetzt eine spezielle Funktion, die CRAN nach ihrer Rückkehr aus dem Urlaub übermittelt wird. naniar.njtierney.com/reference/gg_miss_upset.html
Nick Tierney
6
summary(airquality)

gibt Ihnen diese Informationen bereits

Die VIM- Pakete bieten auch ein schönes Diagramm für fehlende Daten für data.frame

library("VIM")
aggr(airquality)

Geben Sie hier die Bildbeschreibung ein

Steffen Moritz
quelle
Kann das VIM-Paket melden, bei welchen spezifischen Beobachtungen Daten fehlen?
Anthony Simon Mielniczuk
glaube nicht .. aber du kannst das ganz einfach bekommen (du müsstest die Luftqualität durch deinen eigenen Datenrahmen ersetzen): res <- Luftqualität [rowSums (is.na (Luftqualität))> 0,]
Steffen Moritz
4

Prägnanter: sum(is.na(x[1]))

Das ist

  1. x[1] Schauen Sie sich die erste Spalte an

  2. is.na() wahr, wenn es ist NA

  3. sum() TRUEist 1, FALSEist0

Keith Whittingham
quelle
Dies beantwortet nicht die ursprüngliche Frage, nämlich die Anzahl der NAs für alle Spalten in den Daten zu finden
Ben Bolker
4

Eine weitere grafische Alternative - plot_missingFunktion aus ausgezeichnetem DataExplorerPaket:

Geben Sie hier die Bildbeschreibung ein

Docs weist auch darauf hin, dass Sie diese Ergebnisse für zusätzliche Analysen mit speichern können missing_data <- plot_missing(data).

Radek
quelle
Die plot_missing()Funktion im DataExplorerPaket ist jetzt PlotMissing().
Coip
1
@coip PlotMissing()ist veraltet. Bitte verwenden Sie plot_missing()stattdessen. Siehe # 49 für weitere Details.
Boxuan
2

Eine weitere Funktion, mit der Sie fehlende Daten anzeigen können, ist df_status aus der funModeling-Bibliothek

library(funModeling)

iris.2 ist der Iris-Datensatz mit einigen hinzugefügten NAs. Sie können diesen durch Ihren Datensatz ersetzen.

df_status(iris.2)

Dies gibt Ihnen die Anzahl und den Prozentsatz der NAs in jeder Spalte.

Shahan Degamwala
quelle
1

Für eine weitere grafische Lösung bietet das visdat Paket Angebote vis_miss.

library(visdat)
vis_miss(airquality)

Geben Sie hier die Bildbeschreibung ein

Sehr ähnlich der AmeliaAusgabe mit einem kleinen Unterschied von% s bei Fehlschlägen.

Radek
quelle
1

Ich denke, die Amelia-Bibliothek leistet gute Arbeit beim Umgang mit fehlenden Daten. Sie enthält auch eine Karte zur Visualisierung der fehlenden Zeilen.

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

Geben Sie hier die Bildbeschreibung ein

Sie können auch den folgenden Code ausführen, der die logischen Werte von na zurückgibt

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

Eine andere grafische und interaktive Möglichkeit ist die Verwendung der is.na10Funktion aus der heatmaplyBibliothek:

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"))

Geben Sie hier die Bildbeschreibung ein

Funktioniert wahrscheinlich nicht gut mit großen Datenmengen.

Radek
quelle
0

Wenn Sie dies für eine bestimmte Spalte tun möchten, können Sie dies auch verwenden

length(which(is.na(airquality[1])==T))
Chintak Chhapia
quelle
4
Sie müssen einen logischen Vektor nicht mit T vergleichen. Sie können auch die Anzahl der WAHREN Elemente in einem logischen Vektor zählen, indem Sie ihn summieren.
Houshalter
0

Eine dplyrLösung, um die Zählung zu erhalten, könnte sein:

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

Oder um einen Prozentsatz zu erhalten:

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

Vielleicht ist es auch erwähnenswert, dass fehlende Daten hässlich, inkonsistent und nicht immer NAabhängig von der Quelle oder der Art und Weise, wie sie beim Import behandelt werden, codiert werden können. Die folgende Funktion kann abhängig von Ihren Daten und dem, was Sie als vermisst betrachten möchten, optimiert werden:

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
sbha
quelle