1061 Stimmen

Zeilen mit allen oder einigen NAs (fehlenden Werten) im data.frame entfernen

Ich würde gerne die Zeilen in diesem Datenrahmen entfernen, die:

a) enthalten NA s über alle Spalten hinweg. Nachfolgend finden Sie ein Beispiel für einen Datenrahmen.

             gene hsap mmul mmus rnor cfam
1 ENSG00000208234    0   NA   NA   NA   NA
2 ENSG00000199674    0   2    2    2    2
3 ENSG00000221622    0   NA   NA   NA   NA
4 ENSG00000207604    0   NA   NA   1    2
5 ENSG00000207431    0   NA   NA   NA   NA
6 ENSG00000221312    0   1    2    3    2

Im Grunde möchte ich einen Datenrahmen wie den folgenden erhalten.

             gene hsap mmul mmus rnor cfam
2 ENSG00000199674    0   2    2    2    2
6 ENSG00000221312    0   1    2    3    2

b) enthalten NA s nur in einigen Spalten so kann ich auch dieses Ergebnis erhalten:

             gene hsap mmul mmus rnor cfam
2 ENSG00000199674    0   2    2    2    2
4 ENSG00000207604    0   NA   NA   1    2
6 ENSG00000221312    0   1    2    3    2

55voto

C8H10N4O2 Punkte 16753

Wenn Leistung eine Priorität ist, verwenden Sie data.table y na.omit() mit optionalem Parameter cols= .

na.omit.data.table ist bei meinem Benchmark (siehe unten) am schnellsten, ob für alle Spalten oder für ausgewählte Spalten (OP-Frage Teil 2).

Wenn Sie nicht möchten, dass data.table verwenden complete.cases() .

Bei einer Vanille data.frame , complete.cases ist schneller als na.omit() o dplyr::drop_na() . Beachten Sie, dass na.omit.data.frame unterstützt nicht cols= .

Benchmark-Ergebnis

Hier ist ein Vergleich der Basis (blau), dplyr (rosa), und data.table (gelb) Methoden zum Weglassen entweder aller oder ausgewählter fehlender Beobachtungen bei einem fiktiven Datensatz von 1 Million Beobachtungen von 20 numerischen Variablen mit einer unabhängigen Wahrscheinlichkeit von 5 %, dass sie fehlen, und einer Teilmenge von 4 Variablen für Teil 2.

Ihre Ergebnisse können je nach Länge, Breite und Spärlichkeit Ihres speziellen Datensatzes variieren.

Beachten Sie die logarithmische Skala auf der y-Achse.

enter image description here

Benchmark-Skript

#-------  Adjust these assumptions for your own use case  ------------
row_size   <- 1e6L 
col_size   <- 20    # not including ID column
p_missing  <- 0.05   # likelihood of missing observation (except ID col)
col_subset <- 18:21  # second part of question: filter on select columns

#-------  System info for benchmark  ----------------------------------
R.version # R version 3.4.3 (2017-11-30), platform = x86_64-w64-mingw32
library(data.table); packageVersion('data.table') # 1.10.4.3
library(dplyr);      packageVersion('dplyr')      # 0.7.4
library(tidyr);      packageVersion('tidyr')      # 0.8.0
library(microbenchmark)

#-------  Example dataset using above assumptions  --------------------
fakeData <- function(m, n, p){
  set.seed(123)
  m <-  matrix(runif(m*n), nrow=m, ncol=n)
  m[m<p] <- NA
  return(m)
}
df <- cbind( data.frame(id = paste0('ID',seq(row_size)), 
                        stringsAsFactors = FALSE),
             data.frame(fakeData(row_size, col_size, p_missing) )
             )
dt <- data.table(df)

par(las=3, mfcol=c(1,2), mar=c(22,4,1,1)+0.1)
boxplot(
  microbenchmark(
    df[complete.cases(df), ],
    na.omit(df),
    df %>% drop_na,
    dt[complete.cases(dt), ],
    na.omit(dt)
  ), xlab='', 
  main = 'Performance: Drop any NA observation',
  col=c(rep('lightblue',2),'salmon',rep('beige',2))
)
boxplot(
  microbenchmark(
    df[complete.cases(df[,col_subset]), ],
    #na.omit(df), # col subset not supported in na.omit.data.frame
    df %>% drop_na(col_subset),
    dt[complete.cases(dt[,col_subset,with=FALSE]), ],
    na.omit(dt, cols=col_subset) # see ?na.omit.data.table
  ), xlab='', 
  main = 'Performance: Drop NA obs. in select cols',
  col=c('lightblue','salmon',rep('beige',2))
)

54voto

getting-there Punkte 1381

Eine weitere Option, wenn Sie mehr Kontrolle darüber haben wollen, wie Zeilen als ungültig eingestuft werden, ist

final <- final[!(is.na(final$rnor)) | !(is.na(rawdata$cfam)),]

Unter Verwendung der obigen Angaben, dies:

             gene hsap mmul mmus rnor cfam
1 ENSG00000208234    0   NA   NA   NA   2
2 ENSG00000199674    0   2    2    2    2
3 ENSG00000221622    0   NA   NA   2   NA
4 ENSG00000207604    0   NA   NA   1    2
5 ENSG00000207431    0   NA   NA   NA   NA
6 ENSG00000221312    0   1    2    3    2

Wird:

             gene hsap mmul mmus rnor cfam
1 ENSG00000208234    0   NA   NA   NA   2
2 ENSG00000199674    0   2    2    2    2
3 ENSG00000221622    0   NA   NA   2   NA
4 ENSG00000207604    0   NA   NA   1    2
6 ENSG00000221312    0   1    2    3    2

...wobei nur Zeile 5 entfernt wird, da sie die einzige Zeile ist, die NAs für beide enthält rnor UND cfam . Die boolesche Logik kann dann entsprechend den spezifischen Anforderungen geändert werden.

23voto

Raminsu Punkte 299

Mit dem Paket dplyr können wir NA wie folgt filtern:

dplyr::filter(df,  !is.na(columnname))

19voto

LegitMe Punkte 550

Zu Ihrer ersten Frage: Ich habe einen Code, mit dem ich alle NAs loswerden kann. Danke an @Gregor, dass er es einfacher macht.

final[!(rowSums(is.na(final))),]

Für die zweite Frage ist der Code nur eine Abwandlung der vorherigen Lösung.

final[as.logical((rowSums(is.na(final))-5)),]

Beachten Sie, dass die -5 die Anzahl der Spalten in Ihren Daten ist. Dadurch werden Zeilen mit allen NAs eliminiert, da die rowSums sich zu 5 addieren und sie nach der Subtraktion zu Nullen werden. Dieses Mal ist as.logical erforderlich.

19voto

bschneidr Punkte 5580

Eine Herangehensweise, die sowohl allgemein ist als auch recht gut lesbaren Code ergibt, ist die Verwendung der filter() Funktion und die Funktion across() Hilfsfunktionen aus dem Paket {dplyr}.

library(dplyr)

vars_to_check <- c("rnor", "cfam")

# Filter a specific list of columns to keep only non-missing entries

df %>% 
  filter(across(one_of(vars_to_check),
                ~ !is.na(.x)))

# Filter all the columns to exclude NA
df %>% 
  filter(across(everything(),
                ~ !is.na(.)))

# Filter only numeric columns
df %>%
  filter(across(where(is.numeric),
                ~ !is.na(.)))

In ähnlicher Weise gibt es auch die Variantenfunktionen im dplyr-Paket ( filter_all , filter_at , filter_if ), die das Gleiche bewirken:

library(dplyr)

vars_to_check <- c("rnor", "cfam")

# Filter a specific list of columns to keep only non-missing entries
df %>% 
  filter_at(.vars = vars(one_of(vars_to_check)),
            ~ !is.na(.))

# Filter all the columns to exclude NA
df %>% 
  filter_all(~ !is.na(.))

# Filter only numeric columns
df %>%
  filter_if(is.numeric,
            ~ !is.na(.))

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X