Eliminar columnas del marco de datos donde TODOS los valores son NA
Tengo un marco de datos donde algunas de las columnas contienen valores NA.
¿ Cómo puedo eliminar columnas donde todas las filas contienen valores NA?
Prueba esto:
df <- df[,colSums(is.na(df))<nrow(df)]
Los dos enfoques ofrecidos hasta ahora fallan con grandes conjuntos de datos ya que (entre otros problemas de memoria) crean is.na(df)
, que será un objeto del mismo tamaño que df
.
Aquí hay dos enfoques que son más eficientes en memoria y tiempo.
Un enfoque utilizandoFilter
Filter(function(x)!all(is.na(x)), df)
y un enfoque que utiliza data.table (para eficiencia general de tiempo y memoria)
library(data.table)
DT <- as.data.table(df)
DT[,which(unlist(lapply(DT, function(x)!all(is.na(x))))),with=F]
ejemplos que utilizan datos grandes (30 columnas, 1e6 filas)
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
Actualizar
Ahora puede utilizarlo select
con el where
asistente de selección. select_if
está reemplazado, pero sigue funcionando a partir de dplyr 1.0.2. (gracias a @mcstrother por llamar la atención sobre esto).
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(where(not_all_na))
x y
1 1 1
2 2 2
3 3 NA
4 4 4
5 5 5
> temp %>% select(where(not_any_na))
x
1 1
2 2
3 3
4 4
5 5
Antigua respuesta
dplyr
ahora tiene un select_if
verbo que puede ser útil aquí:
> 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