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:
ave(x, y, FUN = sum)
заменяетx
записи со значениями, суммированными в группе, где каждая группа состоит изx
значения с одинаковымиy
составная часть. Возвращаемый объект - это вектор длиныlength(x)
,tapply(x, y, sum)
суммыx
значения для каждой группы; возвращаемый объект - это массив, который имеет то же количество измерений, что иy
имеет уникальные группы.by(x, y, sum)
также суммыx
значения для каждой группы; возвращаемый объект - это список, который имеет то же количество записей, что иy
имеет уникальные группы.
Возможно, еще один способ думать о разнице между ave
против tapply
/by
в контексте dplyr
синтаксис:
ave
соответствуетgroup_by
+mutate
заявление:data.frame(x, y) %>% group_by(y) %>% mutate(x = sum(x)) %>% pull(x)
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
, так далее.).