R使用aggregate()输出来输入NA

时间:2014-07-16 23:52:12

标签: r aggregate-functions apply missing-data

我有一个数据集,我想为其遗漏缺失值。我不想使用列中位数,而是使用类别中位数。我可以创建一个聚合,但我想知道将这两个部分集成的最佳方法是什么。这是一个玩具数据集。

df1 <- iris

set.seed(456)
df1[sample(nrow(df1), 30, replace = F), 'Sepal.Length'] <- NA

set.seed(456)
df1[sample(nrow(df1), 30, replace = F), 'Sepal.Width'] <- NA

set.seed(456)
df1[sample(nrow(df1), 30, replace = F), 'Petal.Length'] <- NA

set.seed(456)
df1[sample(nrow(df1), 30, replace = F), 'Petal.Width'] <- NA

agg1 <- aggregate(. ~ Species, data = df1, FUN = median)

我知道我可以使用一堆ifelse()'s和循环来做到这一点,但我认为这是一种更优雅的方式。任何建议将不胜感激。

编辑: 这就是我自己想出的:

for(i in names(df1)[sapply(df1, is.numeric)]){  # i = "Sepal.Length"

    for(k in agg1$Species){
        df1[,i] <- ifelse(is.na(df1[,i]), agg1[which(agg1$Species == k),i], df1[,i])
    }

}

4 个答案:

答案 0 :(得分:1)

有几种方法可以对此操作进行矢量化。

如果行的顺序不重要(即,您很乐意最后追加所有插补的行),那么以下是一个选项:

df2 <- rbind(na.omit(df1),
             agg1[match(df1[!complete.cases(df1), 'Species'], agg1$Species), ])

或者,merge可用于保留行顺序(这可能更可取):

df1[!complete.cases(df1), -5] <- 
  merge(agg1, df1[!complete.cases(df1), 'Species', drop=FALSE], 
        by='Species')[, -c(1, 5)]

答案 1 :(得分:0)

您也可以使用dplyr

library(dplyr)
library(tidyr)

获取中值

dfMed <- df1%>%
gather(Var,Val, Sepal.Length:Petal.Width)%>%
group_by(Species, Var) %>% 
summarize(Val=median(Val, na.rm=T))%>% 
spread(Var,Val)


 dfMed
# Source: local data frame [3 x 5]

#      Species Sepal.Length Sepal.Width Petal.Length Petal.Width
# 1     setosa          5.0         3.4         1.45         0.2
# 2 versicolor          5.9         2.9         4.40         1.3
# 3  virginica          6.4         3.0         5.50         2.0

inner_join NA行df1

的结果
dfJoin <- inner_join(dfMed, df1%>%
do(filter(., !complete.cases(.))), by="Species")[,c(2:5,1)]

dfJoin

替换缺失值行
df1[!df1%>% complete.cases(),] <- dfJoin 

答案 2 :(得分:0)

使用data.table

首先我们将您的数据发送到data.table

setDT(df1)

然后我们得到agg1

agg1 = df1[, lapply(.SD, median, na.rm=TRUE), by=Species]
setcolorder(agg1, chmatch(names(df1), names(agg1)))

现在,我们用基于二进制搜索的子集(比矢量扫描更快的速度)用引用(不会复制)的值替换NA s agg1一次,仅适用于所有NA s的行:

cols = names(df1)
setkey(agg1, Species)
df1[is.na(Sepal.Length) & is.na(Sepal.Width) & is.na(Petal.Length) & 
    is.na(Petal.Width), (cols) := agg1[J(Species)]]

i中的条件完全拼写出来,因为使用complete.cases可能会导致数据集中只有一列或多列中有NA的其他行,如我明白不应该被替换。

答案 3 :(得分:0)

这是我最终使用的内容:

imputeMed <- function(x){
    medX <- median(x, na.rm = T)
    x <- ifelse(is.na(x), medX, x)
    return(x)
}

vtu1 <- names(df1)[sapply(df1, is.numeric)]
specLev <- unique(as.character(df1$Species))

for(i in specLev){  # i = specLev[1]

df1[df1$Species == i,vtu1] <- as.data.frame(lapply(df1[df1$Species == i,vtu1], imputeMed))

}