values sort remove name missing eliminate data column cases r dataframe filter missing-data r-faq

remove - sort data frame r



Eliminar filas con todos o algunos NA(valores perdidos) en data.frame (15)

Si el rendimiento es una prioridad, use data.table y na.omit() con na.omit() opcionales cols= .

na.omit.data.table es el más rápido en mi punto de referencia (ver más abajo), ya sea para todas las columnas o para columnas seleccionadas (pregunta 2 de la parte OP).

Si no desea utilizar data.table , use complete.cases() .

En un data.frame vainilla, complete.cases es más rápido que na.omit() o dplyr::drop_na() . Tenga en cuenta que na.omit.data.frame no admite cols= .

Resultado de referencia

Aquí hay una comparación de los métodos base (azul), dplyr (rosa) y data.table (yellow) para data.table todas las observaciones faltantes o seleccionarlas, en un conjunto de datos nocionales de 1 millón de observaciones de 20 variables numéricas con un 5% de probabilidad independiente de ser faltan, y un subconjunto de 4 variables para la parte 2.

Sus resultados pueden variar según la longitud, el ancho y la dispersión de su conjunto de datos en particular.

Observe la escala de registro en el eje y.

Guión de referencia

#------- Adjust these assumptions for your own use case ------------ row_size <- 1e6L col_size <- 20 # not including ID column p_missing <- 0.05 # likelihood of missing observation (except ID col) col_subset <- 18:21 # second part of question: filter on select columns #------- System info for benchmark ---------------------------------- R.version # R version 3.4.3 (2017-11-30), platform = x86_64-w64-mingw32 library(data.table); packageVersion(''data.table'') # 1.10.4.3 library(dplyr); packageVersion(''dplyr'') # 0.7.4 library(tidyr); packageVersion(''tidyr'') # 0.8.0 library(microbenchmark) #------- Example dataset using above assumptions -------------------- fakeData <- function(m, n, p){ set.seed(123) m <- matrix(runif(m*n), nrow=m, ncol=n) m[m<p] <- NA return(m) } df <- cbind( data.frame(id = paste0(''ID'',seq(row_size)), stringsAsFactors = FALSE), data.frame(fakeData(row_size, col_size, p_missing) ) ) dt <- data.table(df) par(las=3, mfcol=c(1,2), mar=c(22,4,1,1)+0.1) boxplot( microbenchmark( df[complete.cases(df), ], na.omit(df), df %>% drop_na, dt[complete.cases(dt), ], na.omit(dt) ), xlab='''', main = ''Performance: Drop any NA observation'', col=c(rep(''lightblue'',2),''salmon'',rep(''beige'',2)) ) boxplot( microbenchmark( df[complete.cases(df[,col_subset]), ], #na.omit(df), # col subset not supported in na.omit.data.frame df %>% drop_na(col_subset), dt[complete.cases(dt[,col_subset,with=FALSE]), ], na.omit(dt, cols=col_subset) # see ?na.omit.data.table ), xlab='''', main = ''Performance: Drop NA obs. in select cols'', col=c(''lightblue'',''salmon'',rep(''beige'',2)) )

Me gustaría eliminar las líneas en este marco de datos que:

a) contienen NA s en todas las columnas. A continuación se muestra mi ejemplo de marco de datos.

gene hsap mmul mmus rnor cfam 1 ENSG00000208234 0 NA NA NA NA 2 ENSG00000199674 0 2 2 2 2 3 ENSG00000221622 0 NA NA NA NA 4 ENSG00000207604 0 NA NA 1 2 5 ENSG00000207431 0 NA NA NA NA 6 ENSG00000221312 0 1 2 3 2

Básicamente, me gustaría obtener un marco de datos como el siguiente.

gene hsap mmul mmus rnor cfam 2 ENSG00000199674 0 2 2 2 2 6 ENSG00000221312 0 1 2 3 2

b) contiene NA s solo en algunas columnas , por lo que también puedo obtener este resultado:

gene hsap mmul mmus rnor cfam 2 ENSG00000199674 0 2 2 2 2 4 ENSG00000207604 0 NA NA 1 2 6 ENSG00000221312 0 1 2 3 2


Esto devolverá las filas que tienen al menos UN valor no NA.

final[rowSums(is.na(final))<length(final),]

Esto devolverá las filas que tienen al menos DOS valores no NA.

final[rowSums(is.na(final))<(length(final)-1),]


Otra opción si desea un mayor control sobre cómo se considera que las filas no son válidas es

final <- final[!(is.na(final$rnor)) | !(is.na(rawdata$cfam)),]

Usando lo anterior, esto:

gene hsap mmul mmus rnor cfam 1 ENSG00000208234 0 NA NA NA 2 2 ENSG00000199674 0 2 2 2 2 3 ENSG00000221622 0 NA NA 2 NA 4 ENSG00000207604 0 NA NA 1 2 5 ENSG00000207431 0 NA NA NA NA 6 ENSG00000221312 0 1 2 3 2

Se convierte en

gene hsap mmul mmus rnor cfam 1 ENSG00000208234 0 NA NA NA 2 2 ENSG00000199674 0 2 2 2 2 3 ENSG00000221622 0 NA NA 2 NA 4 ENSG00000207604 0 NA NA 1 2 6 ENSG00000221312 0 1 2 3 2

... donde solo se elimina la fila 5, ya que es la única fila que contiene NA para rnor AND cfam . La lógica booleana se puede cambiar para que se ajuste a requisitos específicos.


Para su primera pregunta, tengo un código con el que me siento cómodo para deshacerme de todas las AN. Gracias por @Gregor para hacerlo más simple.

final[!(rowSums(is.na(final))),]

Para la segunda pregunta, el código es solo una alternativa de la solución anterior.

final[as.logical((rowSums(is.na(final))-5)),]

Observe que el -5 es el número de columnas en sus datos. Esto eliminará las filas con todos los NA, ya que rowSums suma hasta 5 y se convierten en ceros después de la resta. Esta vez, as.logical es necesario.


Prefiero la siguiente forma de verificar si las filas contienen NA:

row.has.na <- apply(final, 1, function(x){any(is.na(x))})

Esto devuelve un vector lógico con valores que indican si hay algún NA en una fila. Puedes usarlo para ver cuántas filas tendrás que soltar:

sum(row.has.na)

y finalmente soltarlos

final.filtered <- final[!row.has.na,]

Para filtrar filas con cierta parte de NA, se vuelve un poco más complicado (por ejemplo, puede ingresar ''final [, 5: 6]'' a ''aplicar''). En general, la solución de Joris Meys parece ser más elegante.


Pruebe na.omit(your.data.frame) . En cuanto a la segunda pregunta, intente publicarla como otra pregunta (para mayor claridad).


Si desea controlar la cantidad de NA que son válidas para cada fila, pruebe esta función. Para muchos conjuntos de datos de encuestas, demasiadas respuestas de preguntas en blanco pueden arruinar los resultados. Así que se eliminan después de un cierto umbral. Esta función le permitirá elegir cuántos NA puede tener la fila antes de que se elimine:

delete.na <- function(DF, n=0) { DF[rowSums(is.na(DF)) <= n,] }

Por defecto, eliminará todas las AN:

delete.na(final) gene hsap mmul mmus rnor cfam 2 ENSG00000199674 0 2 2 2 2 6 ENSG00000221312 0 1 2 3 2

O especifique el número máximo de NA permitidas:

delete.na(final, 2) gene hsap mmul mmus rnor cfam 2 ENSG00000199674 0 2 2 2 2 4 ENSG00000207604 0 NA NA 1 2 6 ENSG00000221312 0 1 2 3 2


Si te gustan las tuberías ( %>% ), el nuevo drop_na es tu amigo:

library(tidyr) df %>% drop_na() # gene hsap mmul mmus rnor cfam # 2 ENSG00000199674 0 2 2 2 2 # 6 ENSG00000221312 0 1 2 3 2 df %>% drop_na(rnor, cfam) # gene hsap mmul mmus rnor cfam # 2 ENSG00000199674 0 2 2 2 2 # 4 ENSG00000207604 0 NA NA 1 2 # 6 ENSG00000221312 0 1 2 3 2


Soy un sintetizador :). Aquí combiné las respuestas en una función:

#'' keep rows that have a certain number (range) of NAs anywhere/somewhere and delete others #'' @param df a data frame #'' @param col restrict to the columns where you would like to search for NA; eg, 3, c(3), 2:5, "place", c("place","age") #'' /cr default is NULL, search for all columns #'' @param n integer or vector, 0, c(3,5), number/range of NAs allowed. #'' /cr If a number, the exact number of NAs kept #'' /cr Range includes both ends 3<=n<=5 #'' /cr Range could be -Inf, Inf #'' @return returns a new df with rows that have NA(s) removed #'' @export ez.na.keep = function(df, col=NULL, n=0){ if (!is.null(col)) { # R converts a single row/col to a vector if the parameter col has only one col # see https://radfordneal.wordpress.com/2008/08/20/design-flaws-in-r-2-%E2%80%94-dropped-dimensions/#comments df.temp = df[,col,drop=FALSE] } else { df.temp = df } if (length(n)==1){ if (n==0) { # simply call complete.cases which might be faster result = df[complete.cases(df.temp),] } else { # credit: http://.com/a/30461945/2292993 log <- apply(df.temp, 2, is.na) logindex <- apply(log, 1, function(x) sum(x) == n) result = df[logindex, ] } } if (length(n)==2){ min = n[1]; max = n[2] log <- apply(df.temp, 2, is.na) logindex <- apply(log, 1, function(x) {sum(x) >= min && sum(x) <= max}) result = df[logindex, ] } return(result) }


Supongo que esto podría resolverse de manera más elegante de esta manera.

m <- matrix(1:25, ncol = 5) m[c(1, 6, 13, 25)] <- NA df <- data.frame(m) library(dplyr) df %>% filter_all(any_vars(is.na(.))) #> X1 X2 X3 X4 X5 #> 1 NA NA 11 16 21 #> 2 3 8 NA 18 23 #> 3 5 10 15 20 NA


Suponiendo dat sea ​​su marco de datos, el resultado esperado se puede lograr utilizando

1. rowSums

> dat[!rowSums((is.na(dat))),] gene hsap mmul mmus rnor cfam 2 ENSG00000199674 0 2 2 2 2 6 ENSG00000221312 0 1 2 3 2

2. lapply

> dat[!Reduce(''|'',lapply(dat,is.na)),] gene hsap mmul mmus rnor cfam 2 ENSG00000199674 0 2 2 2 2 6 ENSG00000221312 0 1 2 3 2


También podemos usar la función de subconjunto para esto.

finalData<-subset(data,!(is.na(data["mmul"]) | is.na(data["rnor"])))

Esto dará solo aquellas filas que no tienen NA tanto en mmul como en rnor


También puedes ver las casillas complete.cases :

> final[complete.cases(final), ] gene hsap mmul mmus rnor cfam 2 ENSG00000199674 0 2 2 2 2 6 ENSG00000221312 0 1 2 3 2

na.omit es más agradable solo para eliminar todas las NA . complete.cases permite la selección parcial incluyendo solo ciertas columnas del marco de datos:

> final[complete.cases(final[ , 5:6]),] gene hsap mmul mmus rnor cfam 2 ENSG00000199674 0 2 2 2 2 4 ENSG00000207604 0 NA NA 1 2 6 ENSG00000221312 0 1 2 3 2

Tu solución no puede funcionar. Si insistes en usar is.na , entonces tienes que hacer algo como:

> final[rowSums(is.na(final[ , 5:6])) == 0, ] gene hsap mmul mmus rnor cfam 2 ENSG00000199674 0 2 2 2 2 4 ENSG00000207604 0 NA NA 1 2 6 ENSG00000221312 0 1 2 3 2

pero el uso de complete.cases es mucho más claro y más rápido.


Usando el paquete dplyr podemos filtrar NA de la siguiente manera:

dplyr::filter(df, !is.na(columnname))


delete.dirt <- function(DF, dart=c(''NA'')) { dirty_rows <- apply(DF, 1, function(r) !any(r %in% dart)) DF <- DF[dirty_rows, ] } mydata <- delete.dirt(mydata)

La función anterior elimina todas las filas del marco de datos que tiene ''NA'' en cualquier columna y devuelve los datos resultantes. Si desea comprobar múltiples valores como NA y ? cambiar dart=c(''NA'') en la función param a dart=c(''NA'', ''?'')