Cómo reemplazar NA con media por subconjunto en R (imputar con plyr?)

Tengo un dataframe con la longitud y el ancho de varios artrópodos de las entrañas de las salamandras. Debido a que algunas agallas tenían miles de ciertos artículos de presa, solo medí un subconjunto de cada tipo de presa. Ahora quiero reemplazar cada individuo no medido con el largo y ancho promedio para esa presa. Quiero mantener el dataframe y solo agregar columnas imputadas (longitud2, ancho2). La razón principal es que cada fila también tiene columnas con datos sobre la fecha y la ubicación de la salamandra. Podría completar el NA con una selección aleatoria de los individuos medidos pero, por el bien del argumento, supongamos que solo quiero reemplazar cada NA con la media.

Por ejemplo, imagine que tengo un dataframe que se parece a algo así como:

id taxa length width 101 collembola 2.1 0.9 102 mite 0.9 0.7 103 mite 1.1 0.8 104 collembola NA NA 105 collembola 1.5 0.5 106 mite NA NA 

En realidad, tengo más columnas y alrededor de 25 taxones diferentes y un total de ~ 30,000 artículos presa en total. Parece que el paquete plyr puede ser ideal para esto, pero no puedo entender cómo hacerlo. No soy muy R ni soy un experto en progtwigción, pero estoy tratando de aprender.

No es que yo sepa lo que estoy haciendo, pero intentaré crear un pequeño conjunto de datos para jugar si me sirve.

 exampleDF <- data.frame(id = seq(1:100), taxa = c(rep("collembola", 50), rep("mite", 25), rep("ant", 25)), length = c(rnorm(40, 1, 0.5), rep("NA", 10), rnorm(20, 0.8, 0.1), rep("NA", 5), rnorm(20, 2.5, 0.5), rep("NA", 5)), width = c(rnorm(40, 0.5, 0.25), rep("NA", 10), rnorm(20, 0.3, 0.01), rep("NA", 5), rnorm(20, 1, 0.1), rep("NA", 5))) 

Aquí hay algunas cosas que he intentado (que no han funcionado):

 # mean imputation to recode NA in length and width with means (could do random imputation but unnecessary here) mean.imp <- function(x) { missing <- is.na(x) n.missing <-sum(missing) x.obs <-a[!missing] imputed <- x imputed[missing] <- mean(x.obs) return (imputed) } mean.imp(exampleDF[exampleDF$taxa == "collembola", "length"]) n.taxa <- length(unique(exampleDF$taxa)) for(i in 1:n.taxa) { mean.imp(exampleDF[exampleDF$taxa == unique(exampleDF$taxa[i]), "length"]) } # no way to get back into dataframe in proper places, try plyr? 

otro bash:

 imp.mean <- function(x) { a <- mean(x, na.rm = TRUE) return (ifelse (is.na(x) == TRUE , a, x)) } # tried but not sure how to use this in ddply Diet2 <- ddply(exampleDF, .(taxa), transform, length2 = function(x) { a <- mean(exampleDF$length, na.rm = TRUE) return (ifelse (is.na(exampleDF$length) == TRUE , a, exampleDF$length)) }) 

¿Alguna sugerencia usando plyr o no?

No es mi propia técnica. Lo vi en las tablas hace un tiempo:

 dat <- read.table(text = "id taxa length width 101 collembola 2.1 0.9 102 mite 0.9 0.7 103 mite 1.1 0.8 104 collembola NA NA 105 collembola 1.5 0.5 106 mite NA NA", header=TRUE) library(plyr) impute.mean <- function(x) replace(x, is.na(x), mean(x, na.rm = TRUE)) dat2 <- ddply(dat, ~ taxa, transform, length = impute.mean(length), width = impute.mean(width)) dat2[order(dat2$id), ] #plyr orders by group so we have to reorder 

Editar un enfoque non plyr con un ciclo for :

 for (i in which(sapply(dat, is.numeric))) { for (j in which(is.na(dat[, i]))) { dat[j, i] <- mean(dat[dat[, "taxa"] == dat[j, "taxa"], i], na.rm = TRUE) } } 

Editar muchas lunas más tarde aquí es un enfoque de data.table & dplyr :

tabla de datos

 library(data.table) setDT(dat) dat[, length := impute.mean(length), by = taxa][, width := impute.mean(width), by = taxa] 

dplyr

 library(dplyr) dat %>% group_by(taxa) %>% mutate( length = impute.mean(length), width = impute.mean(width) ) 

Antes de responder a esto, quiero decir que soy un principiante en R. Por lo tanto, hágamelo saber si siente que mi respuesta es incorrecta.

Código:

 DF[is.na(DF$length), "length"] <- mean(na.omit(telecom_original_1$length)) 

y aplique lo mismo para el ancho.

DF representa el nombre del data.frame.

Gracias, Parthi

Ampliando la solución de @Tyler Rinker, supongamos que las features son las columnas a imputar. En este caso, features <- c('length', 'width') . Luego, usando data.table la solución se convierte en:

 library(data.table) setDT(dat) dat[, (features) := lapply(.SD, impute.mean), by = taxa, .SDcols = features]