webentwicklung-frage-antwort-db.com.de

Entfernen Sie Spalten aus dem Datenrahmen, wobei ALLE Werte NA sind

Ich habe Probleme mit einem Datenrahmen und konnte das Problem nicht wirklich selbst lösen:
Das datenrahmen hat willkürlich eigenschaften als Spalten und jede Reihe repräsentiert einen datensatz.

Die Frage ist:
Wie man spalten für wo loswerden ALLES Zeilen der Wert ist NA?

99
Gnark

Versuche dies:

df <- df[,colSums(is.na(df))<nrow(df)]
120
teucer

Die beiden bisher angebotenen Ansätze versagen bei großen Datensätzen, da sie (neben anderen Speicherproblemen) is.na(df) erstellen, das ein Objekt mit der gleichen Größe wie df ist.

Hier sind zwei Ansätze, die speicher- und zeiteffizienter sind

Ein Ansatz, der Filter verwendet

Filter(function(x)!all(is.na(x)), df)

und ein Ansatz unter Verwendung von data.table (für allgemeine Zeit- und Speichereffizienz)

library(data.table)
DT <- as.data.table(df)
DT[,which(unlist(lapply(DT, function(x)!all(is.na(x))))),with=F]

beispiele mit großen Daten (30 Spalten, 1E6 Zeilen)

big_data <- replicate(10, data.frame(rep(NA, 1e6), sample(c(1:8,NA),1e6,T), sample(250,1e6,T)),simplify=F)
bd <- do.call(data.frame,big_data)
names(bd) <- paste0('X',seq_len(30))
DT <- as.data.table(bd)

system.time({df1 <- bd[,colSums(is.na(bd) < nrow(bd))]})
# error -- can't allocate vector of size ...
system.time({df2 <- bd[, !apply(is.na(bd), 2, all)]})
# error -- can't allocate vector of size ...
system.time({df3 <- Filter(function(x)!all(is.na(x)), bd)})
## user  system elapsed 
## 0.26    0.03    0.29 
system.time({DT1 <- DT[,which(unlist(lapply(DT, function(x)!all(is.na(x))))),with=F]})
## user  system elapsed 
## 0.14    0.03    0.18 
77
mnel

dplyr hat jetzt ein select_if-Verb, das hier hilfreich sein kann:

library(dplyr)
temp <- data.frame(x = 1:5, y = c(1,2,NA,4, 5), z = rep(NA, 5))
not_all_na <- function(x) any(!is.na(x))
not_any_na <- function(x) all(!is.na(x))

> temp
  x  y  z
1 1  1 NA
2 2  2 NA
3 3 NA NA
4 4  4 NA
5 5  5 NA

> temp %>% select_if(not_all_na)
  x  y
1 1  1
2 2  2
3 3 NA
4 4  4
5 5  5

> temp %>% select_if(not_any_na)
  x
1 1
2 2
3 3
4 4
5 5
15
zack

Eine andere Möglichkeit wäre die Verwendung der Funktion apply().

Wenn Sie den Datenrahmen haben

df <- data.frame (var1 = c(1:7,NA),
                  var2 = c(1,2,1,3,4,NA,NA,9),
                  var3 = c(NA)
                  )

dann können Sie mit apply() sehen, welche Spalten Ihre Bedingung erfüllen, und Sie können einfach dasselbe Subsetting wie in der Antwort von Musa durchführen, nur mit einem apply-Ansatz.

> !apply (is.na(df), 2, all)
 var1  var2  var3 
 TRUE  TRUE FALSE 

> df[, !apply(is.na(df), 2, all)]
  var1 var2
1    1    1
2    2    2
3    3    1
4    4    3
5    5    4
6    6   NA
7    7   NA
8   NA    9
14
mropa
df[sapply(df, function(x) all(is.na(x)))] <- NULL
5
Joe

Ich hoffe das kann auch helfen. Man könnte es in einen einzigen Befehl umwandeln, aber ich fand es einfacher zu lesen, indem ich es in zwei Befehle teilte. Ich machte eine Funktion mit der folgenden Anweisung und arbeitete blitzschnell.

naColsRemoval = function (DataTable) { na.cols = DataTable [ , .( which ( apply ( is.na ( .SD ) , 2 , all ) ) )] DataTable [ , unlist (na.cols) := NULL , with = F] }

.SD erlaubt es, die Überprüfung auf einen Teil der Tabelle zu beschränken, wenn Sie möchten

1
Luis M. Nieves

Spät zum Spiel, aber Sie können auch das Paket janitor verwenden. Diese Funktion entfernt Spalten, die alle NA sind, und kann geändert werden, um auch Zeilen zu entfernen, die alle NA sind.

df <- janitor::remove_empty(df, which = "cols")

0
André.B

Die akzeptierte Antwort funktioniert nicht bei nicht numerischen Spalten. Ab dieser Antwort arbeitet das Folgende mit Spalten, die verschiedene Datentypen enthalten

Filter(function(x) !all(is.na(x)), df)
0
jeromeResearch