¿Cómo puedo eliminar columnas que tienen más de un umbral de NA? o en porcentaje (digamos más del 50%)?
discipulus
2
@lovedynasty Probablemente sea mejor enviar una pregunta por separado, asumiendo que no lo ha hecho desde que publicó su comentario. Pero de todos modos, siempre puede hacer algo como, por df[, colSums(is.na(df)) < nrow(df) * 0.5]ejemplo, mantener solo columnas con al menos un 50% de espacios en blanco.
MadScone
2
Las personas que trabajan con una matriz de correlación deben usar, df[, colSums(is.na(df)) != nrow(df) - 1]ya que la diagonal es siempre1
Boern
9
También puede usar esto con la función dplyr (versión 0.5.0) select_if. df %>% select_if(colSums(!is.na(.)) > 0)
Stefan Avey
@MadScone me está dando un error de sintaxis en "," para df [, colSums (is.na (df))! = Nrow (df)] y error de sintaxis en "!" en df [colSums (! is.na (df))> 0]. ¿Me estoy perdiendo algo
janitor::remove_empty_cols()está en desuso - usedf <- janitor::remove_empty(df, which = "cols")
André.B
24
Parece que desea eliminar SOLO columnas con TODAS lasNA s, dejando columnas con algunas filas que tienen NAs. Haría esto (pero estoy seguro de que hay una solución vectorizada eficiente:
#set seed for reproducibility
set.seed <- 103
df <- data.frame( id = 1:10 , nas = rep( NA , 10 ) , vals = sample( c( 1:3 , NA ) , 10 , repl = TRUE ) )
df
# id nas vals# 1 1 NA NA# 2 2 NA 2# 3 3 NA 1# 4 4 NA 2# 5 5 NA 2# 6 6 NA 3# 7 7 NA 2# 8 8 NA 3# 9 9 NA 3# 10 10 NA 2#Use this command to remove columns that are entirely NA values, it will elave columns where only some vlaues are NA
df[ , ! apply( df , 2 , function(x) all(is.na(x)) ) ]
# id vals# 1 1 NA# 2 2 2# 3 3 1# 4 4 2# 5 5 2# 6 6 3# 7 7 2# 8 8 3# 9 9 3# 10 10 2
Si se encuentra en la situación en la que desea eliminar columnas que tienen algún NAvalor, simplemente puede cambiar el allcomando anterior a any.
El data.frame tiene dos tipos de columnas: una en whohc todos los valores son números y la otra en la que todos los valores son NA
Lorenzo Rigamonti
Entonces esto funcionará. Solo elimina las columnas donde están TODOS los valores NA.
Simon O'Hanlon
1
Buena solución. Sin apply(is.na(df), 1, all)embargo, lo haría solo porque es un poco más ordenado y is.na()se usa en todas en dflugar de en una fila a la vez (demuestre ser un poco más rápido).
MadScone
@MadScone buen consejo: se ve más ordenado. Sin embargo, debe aplicar en columnas, no en filas.
Simon O'Hanlon
Las ediciones de @MadScone se bloquean después de 5 minutos en los comentarios. ¡No debería preocuparme, no es gran cosa! :-)
Simon O'Hanlon
19
Una secuencia de comandos intuitiva: dplyr::select_if(~!all(is.na(.))). Literalmente mantiene solo las columnas que faltan no todos los elementos. (para eliminar las columnas que faltan todos los elementos).
> df <- data.frame( id = 1:10 , nas = rep( NA , 10 ) , vals = sample( c( 1:3 , NA ) , 10 , repl = TRUE ) )
> df %>% glimpse()
Observations: 10
Variables: 3
$ id <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
$ nas <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA
$ vals <int> NA, 1, 1, NA, 1, 1, 1, 2, 3, NA
> df %>% select_if(~!all(is.na(.)))
id vals
11NA22133144NA5516617718829931010NA
Unit: microseconds
expr min lq mean median uq max neval cld
MadSconeF1 154.5178.35257.9396196.05219.255001.01000 a
MadSconeF2 180.4209.75281.2541226.40251.056322.11000 a
BradCannell 2579.42884.903330.37003059.453379.3033667.31000 d
SimonOHanlon 511.0565.00943.3089586.45623.65210338.41000 b
SiboJiang 2558.12853.053377.67023010.303310.0089718.01000 d
jsta 1544.81652.452031.50651706.051872.6511594.91000 c
akrun 93.8111.60139.9482121.90135.453851.21000 a
autoplot(mbm)
A veces, la primera iteración es un JIT compilado, por lo que tiene tiempos muy pobres y no muy característicos. Creo que es interesante lo que hace el tamaño de muestra más grande en las colas correctas de la distribución. Este es un buen trabajo.
EngrStudent
Lo ejecuté una vez más, no estaba seguro de haber cambiado la trama. En cuanto a la distribución, de hecho. Probablemente debería comparar diferentes tamaños de muestra cuando tenga tiempo.
DJV
1
si qqplot ( ggplot2.tidyverse.org/reference/geom_qq.html ) una de las tendencias, como "akrun", apuesto a que hay un punto que es muy diferente de la distribución del resto. El resto representa cuánto tiempo lleva si lo ejecuta repetidamente, pero eso representa lo que sucede si lo ejecuta una vez. Hay un viejo dicho: puedes tener 20 años de experiencia o solo puedes tener un año de experiencia 20 veces.
IngrStudent
¡muy agradable! Me sorprende que varias muestras estén en la cola extrema. Me pregunto por qué son mucho más costosos. JIT puede ser 1 o 2 pero no 20. ¿Condición? ¿Interrumpe? ¿Otro? Gracias nuevamente por la actualización.
EngrStudent
De nada, gracias por los pensamientos. No sé, de hecho lo dejé correr "libremente".
head(data)
? ¿Quiere eliminar las columnas o filas correspondientes?Respuestas:
Una forma de hacerlo:
Si el recuento de NA en una columna es igual al número de filas, debe ser totalmente NA.
O de manera similar
df[colSums(!is.na(df)) > 0]
fuente
df[, colSums(is.na(df)) < nrow(df) * 0.5]
ejemplo, mantener solo columnas con al menos un 50% de espacios en blanco.df[, colSums(is.na(df)) != nrow(df) - 1]
ya que la diagonal es siempre1
df %>% select_if(colSums(!is.na(.)) > 0)
Aquí hay una solución dplyr:
df %>% select_if(~sum(!is.na(.)) > 0)
fuente
Otra opción es el
janitor
paquete:https://github.com/sfirke/janitor
fuente
janitor::remove_empty_cols()
está en desuso - usedf <- janitor::remove_empty(df, which = "cols")
Parece que desea eliminar SOLO columnas con TODAS las
NA
s, dejando columnas con algunas filas que tienenNA
s. Haría esto (pero estoy seguro de que hay una solución vectorizada eficiente:#set seed for reproducibility set.seed <- 103 df <- data.frame( id = 1:10 , nas = rep( NA , 10 ) , vals = sample( c( 1:3 , NA ) , 10 , repl = TRUE ) ) df # id nas vals # 1 1 NA NA # 2 2 NA 2 # 3 3 NA 1 # 4 4 NA 2 # 5 5 NA 2 # 6 6 NA 3 # 7 7 NA 2 # 8 8 NA 3 # 9 9 NA 3 # 10 10 NA 2 #Use this command to remove columns that are entirely NA values, it will elave columns where only some vlaues are NA df[ , ! apply( df , 2 , function(x) all(is.na(x)) ) ] # id vals # 1 1 NA # 2 2 2 # 3 3 1 # 4 4 2 # 5 5 2 # 6 6 3 # 7 7 2 # 8 8 3 # 9 9 3 # 10 10 2
Si se encuentra en la situación en la que desea eliminar columnas que tienen algún
NA
valor, simplemente puede cambiar elall
comando anterior aany
.fuente
NA
.apply(is.na(df), 1, all)
embargo, lo haría solo porque es un poco más ordenado yis.na()
se usa en todas endf
lugar de en una fila a la vez (demuestre ser un poco más rápido).Una secuencia de comandos intuitiva:
dplyr::select_if(~!all(is.na(.)))
. Literalmente mantiene solo las columnas que faltan no todos los elementos. (para eliminar las columnas que faltan todos los elementos).> df <- data.frame( id = 1:10 , nas = rep( NA , 10 ) , vals = sample( c( 1:3 , NA ) , 10 , repl = TRUE ) ) > df %>% glimpse() Observations: 10 Variables: 3 $ id <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 $ nas <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA $ vals <int> NA, 1, 1, NA, 1, 1, 1, 2, 3, NA > df %>% select_if(~!all(is.na(.))) id vals 1 1 NA 2 2 1 3 3 1 4 4 NA 5 5 1 6 6 1 7 7 1 8 8 2 9 9 3 10 10 NA
fuente
Otra opcion con
Filter
Filter(function(x) !all(is.na(x)), df)
NOTA: Datos de la publicación de @Simon O'Hanlon.
fuente
Como el rendimiento era realmente importante para mí, comparé todas las funciones anteriores.
NOTA: Datos de la publicación de @Simon O'Hanlon. Solo con el tamaño 15000 en lugar de 10.
library(tidyverse) library(microbenchmark) set.seed(123) df <- data.frame(id = 1:15000, nas = rep(NA, 15000), vals = sample(c(1:3, NA), 15000, repl = TRUE)) df MadSconeF1 <- function(x) x[, colSums(is.na(x)) != nrow(x)] MadSconeF2 <- function(x) x[colSums(!is.na(x)) > 0] BradCannell <- function(x) x %>% select_if(~sum(!is.na(.)) > 0) SimonOHanlon <- function(x) x[ , !apply(x, 2 ,function(y) all(is.na(y)))] jsta <- function(x) janitor::remove_empty(x) SiboJiang <- function(x) x %>% dplyr::select_if(~!all(is.na(.))) akrun <- function(x) Filter(function(y) !all(is.na(y)), x) mbm <- microbenchmark( "MadSconeF1" = {MadSconeF1(df)}, "MadSconeF2" = {MadSconeF2(df)}, "BradCannell" = {BradCannell(df)}, "SimonOHanlon" = {SimonOHanlon(df)}, "SiboJiang" = {SiboJiang(df)}, "jsta" = {jsta(df)}, "akrun" = {akrun(df)}, times = 1000) mbm
Resultados:
Unit: microseconds expr min lq mean median uq max neval cld MadSconeF1 154.5 178.35 257.9396 196.05 219.25 5001.0 1000 a MadSconeF2 180.4 209.75 281.2541 226.40 251.05 6322.1 1000 a BradCannell 2579.4 2884.90 3330.3700 3059.45 3379.30 33667.3 1000 d SimonOHanlon 511.0 565.00 943.3089 586.45 623.65 210338.4 1000 b SiboJiang 2558.1 2853.05 3377.6702 3010.30 3310.00 89718.0 1000 d jsta 1544.8 1652.45 2031.5065 1706.05 1872.65 11594.9 1000 c akrun 93.8 111.60 139.9482 121.90 135.45 3851.2 1000 a autoplot(mbm)
mbm %>% tbl_df() %>% ggplot(aes(sample = time)) + stat_qq() + stat_qq_line() + facet_wrap(~expr, scales = "free")
fuente