2012-02-17 14 views
12

Tengo un marco de datos con las longitudes y anchuras 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 marco de datos 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.Cómo reemplazar NA con media por subconjunto en R (imputar con plyr?)

Por ejemplo imaginar que tengo una trama de datos que se ve algo 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 presas 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 programación, pero estoy tratando de aprender.

No sé 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))) 

Estas son algunas cosas que he probado (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 intento:

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)) 
    }) 

Cualquier sugerencia usando plyr o no?

+7

Debe considerar los paquetes * mouse * para imputar valores. –

+1

el paquete 'mi' también es bastante bueno. 'Amelia' es mucho más rápido que cualquiera de' mice' o 'mi', pero depende de que tus variables sean multivariantes normal – richiemorrisroe

Respuesta

37

No es mi propia técnica que 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 no plyr con un for bucle:

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í hay un data.table & dplyr ap proach:

data.table

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) 
    ) 
+3

@djhocking Gracias a Hadley Descubrí dónde robé esto de: [(LINK)] (http: // www.mail-archive.com/[email protected]/msg58289.html) –

2

Antes de responder a esto, quiero decir que soy un principiante en R. Por lo tanto, por favor avísame si crees que mi respuesta es incorrecta.

Código:

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

y aplicar la misma para el ancho.

DF significa el nombre del data.frame.

Gracias, Parthi

0

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

library(data.table) 
setDT(dat) 

dat[, (features) := lapply(.SD, impute.mean), by = taxa, .SDcols = features] 
Cuestiones relacionadas