我想做什么:按名称和班级排列数据,按年份排序,计算值的平均值并保留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
答案 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)
是必需的,因为该列目前是factor
。 valueMessage
列的输出将再次为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)
必须有更优雅的方式来做到这一点。