Come sostituire NA con media dal sottoinsieme in R (impute con plyr?)
Domanda
Ho una dataframe con le lunghezze e larghezze di vari artropodi dalle viscere del salamandre. Poiché alcuni budella avevano migliaia di alcune prede, ho misurato solo un sottoinsieme di ogni tipo preda. Ora voglio sostituire ogni individuo non misurato con la lunghezza e la larghezza media per quella preda. Voglio mantenere il dataframe e basta aggiungere colonne imputati (length2, width2). La ragione principale è che ogni riga ha anche colonne con i dati relativi alla data e luogo la salamandra è stata raccolta. Potrei riempire il NA con una selezione casuale di individui misurati, ma per amor di discussione supponiamo voglio solo sostituire ogni NA con la media.
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 diversi taxa e un totale di circa 30.000 prede in totale. Sembra che il pacchetto plyr potrebbe essere l'ideale per questo, ma non riesco proprio a capire come fare questo. Io non sono molto esperto di R o di programmazione, ma sto cercando di imparare.
Non che io sappia quello che sto facendo, ma cercherò di creare un piccolo set di dati di giocare con se aiuta.
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))
})
Qualche suggerimento utilizzando plyr o no?
Soluzione
Non la mia tecnica che 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 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)
}
}
Modifica molte lune più tardi ecco un data.table e dplyr approccio:
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)
)
Altri suggerimenti
Prima di rispondere a questo, voglio dire che sono un principiante in R. Quindi, per favore fatemi sapere se si sente la mia risposta è sbagliata.
Codice:
DF[is.na(DF$length), "length"] <- mean(na.omit(telecom_original_1$length))
e applicare la stessa per la larghezza.
DF sta per il nome del data.frame.
Grazie, Parthi
Ampliando la soluzione di @Tyler Rinker, features
supponiamo che sono le colonne 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]