r aggregate na

Colapsar filas donde algunas son todas NA, otras son disjuntas con algunas NA



aggregate (4)

Tengo un marco de datos simple como tal:

ID Col1 Col2 Col3 Col4 1 NA NA NA NA 1 5 10 NA NA 1 NA NA 15 20 2 NA NA NA NA 2 25 30 NA NA 2 NA NA 35 40

Y me gustaría reformatearlo como tal:

ID Col1 Col2 Col3 Col4 1 5 10 15 20 2 25 30 35 40

(tenga en cuenta que el conjunto de datos real tiene miles de filas y los valores provienen de datos biológicos: los NA no siguen un patrón simple, excepto que los NA son disjuntos, y sí, hay exactamente 3 filas para cada ID ).

PASO UNO : deshacerse de las filas que solo tienen valores de NA .

En la superficie esto parecía simple, pero me he encontrado con algunos problemas.

complete.cases(DF) devuelve todo FALSE , por lo que realmente no puedo usar esto para eliminar las filas con todos los NA , como en DF[complete.cases(DF),] . Esto se debe a que todas las filas contienen al menos un NA .

Como los NA quieren propagarse, otros esquemas que usan is.na fallan por la misma razón.

PASO DOS : contraiga las dos filas restantes en una.

Pensando en usar algo como aggregate para lograr esto, pero tiene que haber una manera más fácil que this , que no funciona en absoluto.

Gracias por cualquier consejo


Aquí hay un enfoque de tabla de datos que usa na.omit() en las columnas, agrupadas por ID.

library(data.table) setDT(df)[, lapply(.SD, na.omit), by = ID] # ID Col1 Col2 Col3 Col4 # 1: 1 5 10 15 20 # 2: 2 25 30 35 40


Aquí hay un par de intentos agregados:

aggregate(. ~ ID, data=dat, FUN=na.omit, na.action="na.pass") # ID Col1 Col2 Col3 Col4 #1 1 5 10 15 20 #2 2 25 30 35 40

Dado que aggregate interfaz de fórmula de la aggregate usa na.omit en todos los datos antes de hacer cualquier agrupación, eliminará cada fila de datos, ya que todos contienen al menos un valor de NA . Pruébelo: nrow(na.omit(dat)) devuelve 0 . Entonces, en este caso, use na.pass en aggregate y luego na.omit para omitir los NA que se pasaron.

Alternativamente, no use la interfaz de fórmula y especifique las columnas para agregar manualmente:

aggregate(dat[-1], dat[1], FUN=na.omit ) aggregate(dat[c("Col1","Col2","Col3","Col4")], dat["ID"], FUN=na.omit) # ID Col1 Col2 Col3 Col4 #1 1 5 10 15 20 #2 2 25 30 35 40


Tratar

library(dplyr) DF %>% group_by(ID) %>% summarise_each(funs(sum(., na.rm = TRUE)))

Editar: para tener en cuenta el caso en el que una columna tiene todos los NAs para un determinado ID , necesitamos la función sum_NA() que devuelve NA si todos son NA

txt <- "ID Col1 Col2 Col3 Col4 1 NA NA NA NA 1 5 10 NA NA 1 NA NA 15 20 2 NA NA NA NA 2 NA 30 NA NA 2 NA NA 35 40" DF <- read.table(text = txt, header = TRUE) # original code DF %>% group_by(ID) %>% summarise_each(funs(sum(., na.rm = TRUE))) # `summarise_each()` is deprecated. # Use `summarise_all()`, `summarise_at()` or `summarise_if()` instead. # To map `funs` over all variables, use `summarise_all()` # A tibble: 2 x 5 ID Col1 Col2 Col3 Col4 <int> <int> <int> <int> <int> 1 1 5 10 15 20 2 2 0 30 35 40 sum_NA <- function(x) {if (all(is.na(x))) x[NA_integer_] else sum(x, na.rm = TRUE)} DF %>% group_by(ID) %>% summarise_all(funs(sum_NA)) DF %>% group_by(ID) %>% summarise_if(is.numeric, funs(sum_NA)) # A tibble: 2 x 5 ID Col1 Col2 Col3 Col4 <int> <int> <int> <int> <int> 1 1 5 10 15 20 2 2 NA 30 35 40


la manera simple es:

as.data.frame(lapply(myData[,c(''Col1'',''Col2'',''Col3'',''Col4'')],function(x)[!is.na(x)]))

pero si no todas las columnas tienen el mismo número de valores que no son NA , deberá recortarlos así:

temp <- lapply(myData[,c(''Col1'',''Col2'',''Col3'',''Col4'')],function(x)x[!is.na(x)]) len <- min(sapply(temp,length)) as.data.frame(lapply(temp,`[`,seq(len)))