Применение функции к группе группы (tapply в ddply)

Мой набор данных выглядит так:

d = data.frame(year=rep(2000:2002,each=40),month=rep(c(rep(1:12,3),5,6,7,8),3),species=rep(c(rep(letters[1:12],3),"a","b","g","l"),3),species_group=NA,kg=round(rnorm(120,15,6),digits=2))
d$species_group=ifelse(d$species %in% letters[1:5],"A","B")

Я хотел бы иметь средний вес и количество включенных видов по годам и по группам видов (исключая уровни месяца и видов). Это отлично работает с ddply. Однако я также хотел бы включить значение «качества» моих данных. То есть, если количество видов в месяц сбалансировано или, например, в летние месяцы включено больше видов. Поэтому я подумал, что могу просто рассчитать годовое стандартное отклонение количества уникальных видов в месяц. Я попытался сделать это с помощью tapply в ddply следующим образом:

s=ddply(d,c("year","species_group"),function(x) cbind(n_species=length(unique(x$species)),
                                                   quality=tapply(x,x$month,sd(length(unique(x$species)))),
                                                   kg=sum(x$kg,na.rm=T)))

но это дает мне ошибку

Error in match.fun(FUN) : 'sd(length(unique(x$species)))' is not a function, character or symbol

Я хотел бы получить что-то вроде этого:

output=data.frame(year=rep(2000:2002,each=2),species_group=rep(c("A","B"),3),n_species=rep(c(7,9),3),quality=round(rnorm(6,2,0.3),digits=2),kg=round(rnorm(6,15,6),digits=2))

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

Как я могу заставить свою функцию работать или как я могу сделать это более правильно?

ОТВЕЧАТЬ:

Самое простое решение пришло от Shadow, который заметил мою ошибку в использовании tapply. Кроме того, стандартная ошибка должна быть более подходящей, чем стандартное отклонение, что дает следующую формулу:

 s=ddply(d,c("year","species_group"),function(x) cbind(n_species=length(unique(x$species)),
                                                   quality=sd(tapply(x$species,x$month, function(y) length(unique(y))))/sqrt(length(tapply(x$species,x$month, function(y) length(unique(y))))),
                                                   kg=sum(x$kg,na.rm=T)))

person Wave    schedule 27.02.2014    source источник
comment
Если я правильно понимаю, вы просто неправильно используете tapply. Попробуйте sd(tapply(x$species, x$month, function(y) length(unique(y)))).   -  person shadow    schedule 27.02.2014


Ответы (1)


Непонятно, как вы определяете критерии качества. Итак, как бы я это сделал. Сначала я определяю свои критерии качества в отдельной функции. Обратите внимание, что ваша функция должна возвращать одно значение, а не вектор (в вашем решении вы используете tapply, которое возвращает вектор).

## returns the mean of sd variation per month 
get_quality <- 
  function(species,month)
     mean(tapply(species,month,
              FUN=function(s)sd(as.integer(s))),
     na.rm=TRUE)

Затем я использую его в ddply . Чтобы упростить код, я также создаю функцию для группового применения.

ff <- 
function(x) {
    cbind(n_species=length(unique(x$species)),
        quality= get_quality(x$species,x$month),
        kg=sum(x$kg,na.rm=TRUE))
}
library(plyr)

s=ddply(d,.(year,species_group),ff)


  year species_group n_species   quality     kg
1 2000             A         5 0.4000000 259.68
2 2000             B         7 0.2857143 318.24
3 2001             A         5 0.4000000 285.07
4 2001             B         7 0.2857143 351.54
5 2002             A         5 0.4000000 272.46
6 2002             B         7 0.2857143 331.45
person agstudy    schedule 27.02.2014