Несколько функций в одном заявлении или агрегированном заявлении

Можно ли включить две функции в одно выражение или обобщенную инструкцию?

Ниже я использую два оператора tapply и два агрегатных оператора: один для среднего и один для SD.
Я бы предпочел объединить утверждения.

my.Data = read.table(text = "
  animal    age     sex  weight
       1  adult  female     100
       2  young    male      75
       3  adult    male      90
       4  adult  female      95
       5  young  female      80
", sep = "", header = TRUE)

with(my.Data, tapply(weight, list(age, sex), function(x) {mean(x)}))
with(my.Data, tapply(weight, list(age, sex), function(x) {sd(x)  }))

with(my.Data, aggregate(weight ~ age + sex, FUN = mean)
with(my.Data, aggregate(weight ~ age + sex, FUN =   sd)

# this does not work:

with(my.Data, tapply(weight, list(age, sex), function(x) {mean(x) ; sd(x)}))

# I would also prefer that the output be formatted something similar to that 
# show below.  `aggregate` formats the output perfectly.  I just cannot figure 
# out how to implement two functions in one statement.

  age    sex   mean        sd
adult female   97.5  3.535534
adult   male     90        NA
young female   80.0        NA
young   male     75        NA

Я всегда могу запускать два отдельных оператора и объединять выходные данные. Я просто надеялся, что может быть немного более удобное решение.

Я нашел приведенный ниже ответ: Применить несколько функций к столбцу, используя tapply

f <- function(x) c(mean(x), sd(x))
do.call( rbind, with(my.Data, tapply(weight, list(age, sex), f)) )

Однако ни строки, ни столбцы не помечены.

     [,1]     [,2]
[1,] 97.5 3.535534
[2,] 80.0       NA
[3,] 90.0       NA
[4,] 75.0       NA

Я предпочел бы решение в базе R. Решение из пакета plyr было опубликовано по ссылке выше. Если я могу добавить правильные заголовки строк и столбцов к указанному выше выводу, это будет идеально.

Ответ 1

Но они должны иметь:

with(my.Data, aggregate(weight, list(age, sex), function(x) { c(MEAN=mean(x), SD=sd(x) )}))

with(my.Data, tapply(weight, list(age, sex), function(x) { c(mean(x) , sd(x) )} ))
# Not a nice structure but the results are in there

with(my.Data, aggregate(weight ~ age + sex, FUN =  function(x) c( SD = sd(x), MN= mean(x) ) ) )
    age    sex weight.SD weight.MN
1 adult female  3.535534 97.500000
2 young female        NA 80.000000
3 adult   male        NA 90.000000
4 young   male        NA 75.

Принцип, которым нужно придерживаться, состоит в том, чтобы вернуть вашу функцию "одна вещь", которая может быть либо вектором, либо списком, но не может быть последовательным вызовом двух вызовов функций.

Ответ 2

Если вы хотите использовать data.table, он имеет with и by, встроенные в него:

library(data.table)
myDT <- data.table(my.Data, key="animal")


myDT[, c("mean", "sd") := list(mean(weight), sd(weight)), by=list(age, sex)]


myDT[, list(mean_Aggr=sum(mean(weight)), sd_Aggr=sum(sd(weight))), by=list(age, sex)]
     age    sex mean_Aggr   sd_Aggr
1: adult female     96.0  3.6055513
2: young   male     76.5  2.1213203
3: adult   male     91.0  1.4142136
4: young female     84.5  0.7071068

Я использовал немного другой набор данных, чтобы не иметь значений NA для sd

Ответ 3

В духе совместного использования, если вы знакомы с SQL, вы также можете рассмотреть пакет sqldf. (Акцент добавлен, потому что вам нужно знать, например, что mean - avg, чтобы получить желаемые результаты.)

sqldf("select age, sex, 
      avg(weight) `Wt.Mean`, 
      stdev(weight) `Wt.SD` 
      from `my.Data` 
      group by age, sex")
    age    sex Wt.Mean    Wt.SD
1 adult female    97.5 3.535534
2 adult   male    90.0 0.000000
3 young female    80.0 0.000000
4 young   male    75.0 0.000000

Ответ 4

Reshape позволяет вам передавать 2 функции; reshape2 - нет.

library(reshape)
my.Data = read.table(text = "
  animal    age     sex  weight
       1  adult  female     100
       2  young    male      75
       3  adult    male      90
       4  adult  female      95
       5  young  female      80
", sep = "", header = TRUE)
my.Data[,1]<- NULL
(a1<-  melt(my.Data, id=c("age", "sex"), measured=c("weight")))
(cast(a1, age + sex ~ variable, c(mean, sd), fill=NA))

#     age    sex weight_mean weight_sd
# 1 adult female        97.5  3.535534
# 2 adult   male        90.0        NA
# 3 young female        80.0        NA
# 4 young   male        75.0        NA

Я обязан этим @Ramnath, который отметил этот только вчера.