web-dev-qa-db-fra.com

Supprimer les colonnes de la structure de données où TOUTES les valeurs sont NA

J'ai des problèmes avec un bloc de données et je ne pouvais pas résoudre ce problème moi-même
Le trame de données a arbitraire propriétés en colonnes et chaque rangée représente un ensemble de données.

La question est:
Comment se débarrasser des colonnes où pour TOUT lignes la valeur est NA?

99
Gnark

Essaye ça:

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

Les deux approches proposées jusqu'à présent échouent avec les grands ensembles de données car (entre autres problèmes de mémoire), ils créent is.na(df), qui sera un objet de la même taille que df.

Voici deux approches plus efficaces en termes de mémoire et de temps

Une approche utilisant Filter

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

et une approche utilisant data.table (pour l'efficacité globale du temps et de la mémoire)

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

exemples utilisant des données volumineuses (30 colonnes, 1e ligne)

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 a maintenant un verbe select_if qui peut être utile ici:

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

Une autre solution consisterait à utiliser la fonction apply().

Si vous avez le data.frame

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

alors vous pouvez utiliser apply() pour voir quelles colonnes remplissent votre condition et vous pouvez simplement faire le même sous-ensemble que dans la réponse de Musa, uniquement avec une approche apply.

> !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

J'espère que cela peut aussi aider. Cela pourrait être transformé en une seule commande, mais il m'est plus facile de lire en le divisant en deux commandes. J'ai créé une fonction avec les instructions suivantes et travaillé rapidement.

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

.SD permettra de limiter la vérification à une partie du tableau, si vous le souhaitez, mais le tableau entier sera pris comme suit.

1
Luis M. Nieves

En retard au jeu, mais vous pouvez également utiliser le package janitor. Cette fonction supprime les colonnes qui sont toutes NA et peut être modifiée pour supprimer également les lignes qui sont toutes NA.

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

0
André.B

La réponse acceptée ne fonctionne pas avec des colonnes non numériques. De cette réponse , ce qui suit fonctionne avec des colonnes contenant différents types de données

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