使用NA聚合并保留行

时间:2014-07-09 07:35:25

标签: r aggregate na

我想做什么:按名称和班级排列数据,按年份排序,计算值的平均值并保留valueMessage

示例数据:

name <- c("a", "a", "b", "b")
class <- c("c1", "c1", "c3", "c3")
year <- c("2010", "2010", "2008", "2008")
value <- c(100, 33, 100, 90)
valueMessage <-c(NA, "meh", NA, NA)

df <- data.frame(name, class, year, value, valueMessage)
df 


dat <- aggregate(df$value, list(year = df$year, name = df$name, class=df$class, valueMessage=df$valueMessage), mean)
dat <- dat[with(dat, order(class, name, year)), ]

返回:

year name class valueMessage  x
1 2010    a    c1          meh 33

但是我希望保留NA并返回这样的内容:

year name class valueMessage  x
1 2010    a    c1          meh, NA 66.5
2 2008    b    c3          NA 95

3 个答案:

答案 0 :(得分:4)

我喜欢使用sqldf,因为SQL是一个非常好,简单直观的方法(不需要知道成千上万的R函数及其细节和陷阱):

require(sqldf)
sqldf('
select year, name, class, avg(value), 
       group_concat(distinct case when valueMessage is NULL 
                                  then "NA" 
                                  else valueMessage 
                             end) as valueMessages
from df
group by class, name, year
')

在您修改过的示例中,它将生成此输出:

  year name class avg(value) valueMessages
1 2010    a    c1       66.5        NA,meh
2 2008    b    c3       95.0            NA

答案 1 :(得分:4)

问题在于您尝试进行两种不同的聚合:一种用于“值”列,另一种用于“valueMessage”列。

如果是这种情况,您必须单独执行每个操作并merge,或者查看使用包,例如“data.table”来帮助解决问题。

使用“data.table”,您可以执行以下操作:

library(data.table)
DT <- data.table(df)
DT[, list(value = mean(value), 
          valueMessage = list(unique(valueMessage))), 
   by = list(year, name, class)]
#    year name class value valueMessage
# 1: 2010    a    c1  66.5       NA,meh
# 2: 2008    b    c3  95.0           NA

请注意,“valueMessage”列是list。如果您希望它是字符向量,则可以使用paste。换句话说:

DT[, list(value = mean(value), 
          valueMessage = paste(unique(valueMessage), collapse = ",")), 
   by = list(year, name, class)]

在这里,我假设您只对唯一的“valueMessage”值感兴趣。


如果您想使用基础R aggregate,您可以尝试以下内容:

M1 <- aggregate(value ~ year + name + class, df, mean)
M2 <- aggregate(as.character(valueMessage) ~ year + name + class,
                df, unique, na.action = na.pass)
merge(M1, M2)

我使用了“公式”方法,因为我更喜欢输出。 as.character(valueMessage)是必需的,因为该列目前是factorvalueMessage列的输出将再次为list,但如果您更喜欢paste 1的字符向量,则可以使用匿名函数和length

答案 2 :(得分:0)

快速解决方法,试试这个:

#convert NAs to "U"
x <- ifelse(is.na(df$valueMessage),"U",df$valueMessage)
df$valueMessage <- x
#aggregate
dat <- aggregate(df$value, list(year = df$year, name = df$name, class=df$class, valueMessage=df$valueMessage), mean)
dat <- dat[with(dat, order(class, name, year)), ]
#convert "U" back to NA
dat$valueMessage <- ifelse(dat$valueMessage=="U",NA,dat$valueMessage)

必须有更优雅的方式来做到这一点。