20

我有一个数据框,其中包含来自蝾螈内脏的各种节肢动物的长度和宽度。因为有些内脏有数千种特定的猎物,我只测量了每种猎物类型的一个子集。我现在想用该猎物的平均长度和宽度替换每个未测量的个体。我想保留数据框并只添加估算列(length2,width2)。主要原因是每一行都有关于收集蝾螈的日期和位置的数据列。我可以用随机选择的测量个体来填充 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 包可能是理想的,但我只是不知道如何做到这一点。我不是很懂 R 或编程,但我正在努力学习。

并不是说我知道自己在做什么,但如果有帮助,我会尝试创建一个小数据集来玩。

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

有什么建议么?

4

5 回答 5

45

不是我自己的技术,我不久前在板上看到了它:

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

编辑带有for循环的非 plyr 方法:

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方法:

数据表

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)  
    )
于 2012-02-17T04:38:15.793 回答
4

其他几个选项:

1) 使用的新nafill功能

library(data.table)
setDT(dat)

cols <- c("length", "width")

dat[, (cols) := lapply(.SD, function(x) nafill(x, type = "const", fill = mean(x, na.rm = TRUE)))
    , by = taxa
    , .SDcols = cols][]

2) 带有na.aggregate-function

library(zoo)
library(data.table)
setDT(dat)

cols <- c("length", "width")

dat[, (cols) := lapply(.SD, na.aggregate)
    , by = taxa
    , .SDcols = cols][]

默认函数na.aggregatemean; 如果你想使用另一个函数,你应该用FUN-parameter 指定它(例如:)FUN = median。另请参阅带有?na.aggregate.

当然你也可以在 tidyverse 中使用它:

library(dplyr)
library(zoo)

dat %>% 
  group_by(taxa) %>% 
  mutate_at(cols, na.aggregate)
于 2019-10-28T14:50:54.397 回答
3

在回答这个问题之前,我想说我是 R 的初学者。因此,如果您觉得我的回答有误,请告诉我。

代码:

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

并应用相同的宽度。

DF 代表 data.frame 的名称。

谢谢, 帕蒂

于 2015-09-02T14:10:14.590 回答
1

扩展@Tyler Rinker 的解决方案,假设features是要估算的列。在这种情况下features <- c('length', 'width')。那么使用data.table解决方案就变成了:

library(data.table)
setDT(dat)

dat[, (features) := lapply(.SD, impute.mean), by = taxa, .SDcols = features]
于 2017-01-07T03:59:27.337 回答
-1

我遇到了一个类似的事件,我可以给出一个非常简单的步骤来改变你的列的分组平均值。

library(tidyr)

dataset <- dataset %>% group_by(taxa) %>% mutate(length1= ifelse(is.na(length),mean(length,na.rm = T),length))

View(dataset)

如果我能提供任何进一步的帮助,请告诉我。

于 2020-12-08T07:48:30.207 回答