Eliminar columnas del marco de datos donde TODOS los valores son NA

Resuelto Gnark asked hace 54 años • 14 respuestas

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?

Gnark avatar Jan 01 '70 08:01 Gnark
Aceptado

Prueba esto:

df <- df[,colSums(is.na(df))<nrow(df)]
teucer avatar Apr 15 '2010 09:04 teucer

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 
mnel avatar Sep 27 '2012 05:09 mnel

Actualizar

Ahora puede utilizarlo selectcon el whereasistente de selección. select_ifestá 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

dplyrahora tiene un select_ifverbo 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
zack avatar May 14 '2018 16:05 zack