2012-02-17 7 views
12

Ho un dataframe con le lunghezze e le larghezze di vari artropodi dalle viscere delle salamandre. Poiché alcune viscere avevano migliaia di determinati oggetti di preda, ho misurato solo un sottoinsieme di ciascun tipo di preda. Ora voglio sostituire ogni individuo non misurato con la lunghezza media e la larghezza per quella preda. Voglio mantenere il dataframe e aggiungere solo colonne calcolate (length2, width2). Il motivo principale è che ogni riga contiene anche colonne con dati relativi alla data e alla posizione in cui è stata raccolta la salamandra. Potrei riempire il NA con una selezione casuale degli individui misurati, ma per ragioni ipotizziamo di voler sostituire ogni NA con la media.Come sostituire NA con media per sottoinsieme in R (imputare con plyr?)

Per esempio immaginare ho un dataframe che sembra qualcosa di simile:

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 

In realtà ho più colonne e circa 25 taxa differenti per un totale di circa 30.000 prede in totale. Sembra che il pacchetto plyr potrebbe essere l'ideale per questo, ma non riesco a capire come farlo. Non sono molto esperto di programmazione, ma sto cercando di imparare.

Non so che cosa sto facendo, ma cercherò di creare un piccolo set di dati con cui giocare se è utile.

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

qui ci sono alcune cose che ho provato (che non hanno funzionato):

# 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? 

un altro tentativo:

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

Eventuali suggerimenti utilizzando plyr o no?

+7

Si dovrebbe considerare pacchetto * mouse * per i valori di imputazione. –

+1

anche il pacchetto 'mi' è abbastanza buono. 'Amelia' è molto più veloce rispetto a' top' o 'mi', ma fa affidamento sul fatto che le variabili siano normali multivariate – richiemorrisroe

risposta

37

Non la mia tecnica ho visto sulle tavole un po 'indietro:

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 

Modifica un approccio non plyr con un for ciclo:

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

Modifica molte lune più tardi qui è un data.table & dplyr ap proccio:

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 Grazie a Hadley ho scoperto da dove ho tratto questo da: [(LINK)] (http: // www.mail-archive.com/[email protected]/msg58289.html) –

2

Prima di rispondere a questo, voglio dire che sono un principiante in R. Quindi, si prega di fammi sapere se ritieni che la mia risposta sia sbagliata.

Codice:

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

e applicare lo stesso per la larghezza.

DF sta per nome del data.frame.

Grazie, Parthi

0

Ampliando la soluzione di @Tyler Rinker, supponiamo features sono le colonne da imputare. In questo caso features <- c('length', 'width'). Quindi utilizzando data.table la soluzione diventa:

library(data.table) 
setDT(dat) 

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