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?
Essaye ça:
df <- df[,colSums(is.na(df))<nrow(df)]
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]
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
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
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
df[sapply(df, function(x) all(is.na(x)))] <- NULL
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.
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")
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)