Как заменить NA средним на подмножество в R (вменять plyr?) - PullRequest
15 голосов
/ 17 февраля 2012

У меня есть датафрейм с длинами и ширинами различных членистоногих из кишок саламандр.Поскольку у некоторых кишок были тысячи определенных предметов добычи, я измерил только подмножество каждого типа добычи.Теперь я хочу заменить каждого немеренного человека средней длиной и шириной для этой добычи.Я хочу сохранить датафрейм и просто добавить вмененные столбцы (длина2, ширина2).Основная причина в том, что в каждой строке также есть столбцы с данными о дате и месте сбора саламандры.Я мог бы заполнить NA случайным выбором измеренных индивидуумов, но ради аргумента давайте предположим, что я просто хочу заменить каждое NA средним значением.

Например, представьте, что у меня есть кадр данных, который выглядит примерно так::

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

На самом деле у меня есть больше столбцов и около 25 различных таксонов и в общей сложности ~ 30 000 предметов для добычи.Кажется, пакет plyr может быть идеальным для этого, но я просто не могу понять, как это сделать.Я не очень хорошо разбираюсь в программировании или программировании, но пытаюсь учиться.

Не то, чтобы я знал, что делаю, но я постараюсь создать небольшой набор данных, с которым можно поиграть, если это поможет.

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

Вот несколько вещей, которые я пробовал (которые не сработали):

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

еще одна попытка:

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

Любые предложения с использованием plyrили нет?

Ответы [ 3 ]

38 голосов
/ 17 февраля 2012

Не по моей собственной технике. Я видел это на досках некоторое время назад:

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

Редактировать Подход без plyr с циклом 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)
    }
}

Редактировать много лун позже здесь будет data.table & dplyr подход:

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)  
    )
2 голосов
/ 02 сентября 2015

Прежде чем ответить на это, я хочу сказать, что я новичок в R. Поэтому, пожалуйста, дайте мне знать, если вы чувствуете, что мой ответ неверен.

Код:

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

и примените то же самое к ширине.

DF обозначает имя data.frame.

Спасибо, Парти

1 голос
/ 07 января 2017

Расширяя решение @Tyler Rinker, предположим, что features - это столбцы для вменения. В этом случае features <- c('length', 'width'). Затем с помощью data.table решение становится:

library(data.table)
setDT(dat)

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