R - Ave vs Tapply. Всегда ли уникален (ave)==? Если так, почему один из них существует?

Рассмотрим следующее -

set.seed(1)
x <- runif(100)
y <- sample(c('M', 'F', 'D'), 100, TRUE)
aveResult <- ave(x = x, y, FUN = sum)
tapplyResult <- tapply(x, y, sum)
aveResult <- setNames(aveResult, y)
tapplyResult
aveResult[!duplicated(names(aveResult))]

Результаты обеих функций идентичны, за исключением длины их выходов. Кроме того, это также создает путаницу (усугубляется в результате переработки), как в этом случае.

Есть ли пример, когда одна из функций может делать то, что другая не может?

2 ответа

Решение

ave это очень полезно base R функция, которая является быстрой и эффективной для создания новых столбцов на основе применения функции по группам (ниже приведен простой пример, который создает mean по группам столбцов используя ave, dplyr а также data.table методы).

set.seed(24)
df1 <- data.frame(grp = sample(LETTERS, 1e6, replace = TRUE), val = rnorm(1e6))
system.time(with(df1, ave(val, grp)))
#   user  system elapsed 
#  0.070   0.004   0.073 

library(dplyr)
system.time(df1 %>%
              group_by(grp) %>%
              mutate(new = mean(val)))
#   user  system elapsed 
#  0.159   0.000   0.160 

library(data.table)
system.time(setDT(df1)[, new := mean(val), by = grp])
#  user  system elapsed 
#  0.056   0.000   0.057 

в то время как tapply дает обобщенный вывод. Одно из главных преимуществ ave в том, что нам не нужно беспокоиться о порядке вывода, поскольку он всегда дает вывод в одном и том же порядке строк. Это может измениться даже в некоторых tidyverse функции. Вопрос о том, sortиздание unique значения ave всегда равно tapply - это зависит. Для некоторых функций мы можем получить list вывод в tapply

tapply(1:10, rep(LETTERS[1:3], c(3, 3, 4)), FUN = range)

в то время как ave терпит неудачу здесь, потому что это не будет соответствовать длине каждой группы

ave(1:10, rep(LETTERS[1:3], c(3, 3, 4)), FUN = range)

и дает предупреждение

Просто добавить еще один вариант в данном конкретном случае: есть также by(x, y, FUN = sum),

В качестве дополнения к отличному посту @ akrun, здесь приведен краткий анализ различий в выходных данных между ave, tapply а также by данные примера OPs:

  1. ave(x, y, FUN = sum) заменяет x записи со значениями, суммированными в группе, где каждая группа состоит из x значения с одинаковыми y составная часть. Возвращаемый объект - это вектор длины length(x),

  2. tapply(x, y, sum) суммы x значения для каждой группы; возвращаемый объект - это массив, который имеет то же количество измерений, что и y имеет уникальные группы.

  3. by(x, y, sum) также суммы x значения для каждой группы; возвращаемый объект - это список, который имеет то же количество записей, что и y имеет уникальные группы.


Возможно, еще один способ думать о разнице между ave против tapply/by в контексте dplyrсинтаксис:

  1. ave соответствует group_by+mutate заявление:

    data.frame(x, y) %>% group_by(y) %>% mutate(x = sum(x)) %>% pull(x)
    
  2. tapply/by соответствует group_by+summarise заявление:

    data.frame(x, y) %>% group_by(y) %>% summarise(x = sum(x)) %>% pull(x)
    

Как совершенно справедливо подчеркнул @Onyambu, by а также tapply совсем другие; tapply работает на vectorс, в то время как by может взять любой объект (обычно data.frame, matrix, так далее.).

Другие вопросы по тегам