2013-03-05 11 views
13

Czy jest możliwe uwzględnienie dwóch funkcji w pojedynczym oświadczeniu typu tapply lub aggregate?Wiele funkcji w pojedynczym tapply lub zbiorczym oświadczeniu

Poniżej używam dwóch oświadczeń w formie oświadczeń i dwóch stwierdzeń zbiorczych: jednej dla średniej i drugiej dla SD.
Wolałbym łączyć oświadczenia.

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 

Zawsze mogę uruchomić dwie osobne instrukcje i połączyć dane wyjściowe. Miałem tylko nadzieję, że może być nieco wygodniejsze rozwiązanie.

znalazłem odpowiedź poniżej zamieszczone tutaj: Apply multiple functions to column using tapply

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

Jednak ani wiersze lub kolumny są oznakowane.

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

wolałbym rozwiązanie w bazie R. Rozwiązanie z pakietu plyr został opublikowany w linku powyżej. Jeśli mogę dodać prawidłowe nagłówki wierszy i kolumn do powyższego wyniku, byłoby idealnie.

Odpowiedz

14

Ale te powinny posiadać:

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. 

Zasada być przestrzegane jest mieć swój powrót funkcji „jedna rzecz”, które mogą być albo wektorem lub listę, ale nie może być sukcesywne wywołanie dwóch funkcji połączenia.

+0

Dziękujemy! Dwie agregujące instrukcje działają. Wydaje się, że oświadczenie tapply nie działa, ale mogę użyć podejścia zbiorczego. –

+1

Cóż, myślę, że to "działa", po prostu nie dać ci czegoś, co ładnie się drukuje. Spróbuj 'with (my.Data, tapply (waga, lista (wiek, płeć), funkcja (x) {c (średnia (x), sd (x))})) [1,1]' i baw się z wskaźniki, aby zobaczyć wewnątrz tej macierzy list. –

+0

Rozumiem. Dziękuję Ci. A jeśli umieściłbym całe oświadczenie w colnames() lub rownames(), to otrzymam etykiety. –

8

Jeśli chcesz użyć data.table, ma with i by wbudowane w nim:

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 

użyłem nieco inne dane określone w taki sposób, aby nie mieć NA wartości sd

4

Przekształcenie umożliwia przekazanie 2 funkcji; reshape2 nie.

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 

Zawdzięczam to @Ramnath, który zauważył this wczoraj.

6

W duchu dzielenia się, , jeśli znasz SQL, możesz również rozważyć pakiet "sqldf". (Podkreślenie dodane bo trzeba wiedzieć, na przykład, że jest avgmean w celu uzyskania pożądanych wyników.)

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 
Powiązane problemy