Агрегировать несколько переменных, используя несколько разных FUN в R - PullRequest
0 голосов
/ 30 апреля 2018

Это расширение вопросов, задаваемых здесь: Агрегирование / суммирование нескольких переменных на группу (например, сумма, среднее) .

  • В частности, если у меня несколько переменных на aggregate, есть ли способ изменить FUN, каждая переменная агрегируется на?

Пример:

dat <- data.frame(ID = rep(letters[1:3], each =3), Plot = rep(1:3,3),Val1 = (1:9)*10, Val2 = (1:9)*20)

> dat
  ID Plot Val1 Val2
1  a    1   10   20
2  a    2   20   40
3  a    3   30   60
4  b    1   40   80
5  b    2   50  100
6  b    3   60  120
7  c    1   70  140
8  c    2   80  160
9  c    3   90  180


#Aggregate 2 variables using the *SAME* FUN
  aggregate(cbind(Val1, Val2) ~ ID, dat, sum)

  ID Val1 Val2
1  a   60  120
2  b  150  300
3  c  240  480
  • но обратите внимание, что обе переменные суммируются .

Что, если я хочу взять сумму от Val1 и среднее от Val2 ??

Лучшее решение, которое у меня есть:

merge(
  aggregate(Val1 ~ ID, dat, sum),
  aggregate(Val2 ~ ID, dat, mean),
  by = c('ID')
)
  • Но мне интересно, является ли это более чистым / коротким способом сделать это ...

Могу ли я сделать все это в Aggregate ???

  • (в коде aggregate я ничего не видел, чтобы казалось, что это может сработать, но раньше я ошибался ...)

Пример # 2:

(как запрошено , с использованием mtcars)
Reduce(function(df1, df2) merge(df1, df2, by = c('cyl','am'), all = T),
    list(
    aggregate(hp ~ cyl + am, mtcars, sum, na.rm = T),
    aggregate(wt ~ cyl + am, mtcars, min), 
    aggregate(qsec ~ cyl + am, mtcars, mean, na.rm = T),
    aggregate(mpg ~ cyl + am, mtcars, mean, na.rm = T)
  )
)

#I'd want a straightforward alternative like:
  aggregate(cbind(hp,wt,qsec,mpg) ~ cyl + am, mtcars, list(sum, min, mean, mean), na.rm = T)

  # ^(I know this doesn't work)

Примечание: я бы предпочел базовый подход R, но я уже понимаю, dplyr или какой-то другой пакет, вероятно, делает это "лучше"

Ответы [ 2 ]

0 голосов
/ 30 апреля 2018

Рассмотрим попарное сопоставление столбцов и функций, а затем запустите Map, чтобы создать список агрегированных фреймов данных, поскольку aggregate допускает строковые значения имен функций. Затем запустите Reduce, чтобы объединить все элементы данных.

cols <- names(dat)[grep("Val", names(dat))]
fcts <- c("mean", "sum")

df_list <- Map(function(c, f) aggregate(.~ID, dat[c("ID", c)], FUN=f), cols, fcts)

final_df <- Reduce(function(x,y) merge(x, y, by="ID"), df_list)

final_df
#   ID Val1 Val2
# 1  a   20  120
# 2  b   50  300
# 3  c   80  480

Убедитесь, что столбцы и функции векторы имеют одинаковую длину, возможно, необходимо повторить функции.

И для демонстрации с mtcars :

cols <- c("hp", "wt", "qsec", "mpg")
fcts <- c("sum", "min", "mean", "mean")

df_list <- Map(function(c, f) aggregate(.~cyl+am, mtcars[c("cyl", "am", c)], FUN=f), cols, fcts)

Reduce(function(x,y) merge(x,y, by=c("cyl", "am")), df_list)

#   cyl am   hp    wt     qsec      mpg
# 1   4  0  254 2.465 20.97000 22.90000
# 2   4  1  655 1.513 18.45000 28.07500
# 3   6  0  461 3.215 19.21500 19.12500
# 4   6  1  395 2.620 16.32667 20.56667
# 5   8  0 2330 3.435 17.14250 15.05000
# 6   8  1  599 3.170 14.55000 15.40000
0 голосов
/ 30 апреля 2018

Вы можете использовать summarise из пакета dplyr

library(dplyr)

dat <- data.frame(ID = rep(letters[1:3], each =3), Plot = rep(1:3,3),Val1 = (1:9)*10, Val2 = (1:9)*20)
dat

#>   ID Plot Val1 Val2
#> 1  a    1   10   20
#> 2  a    2   20   40
#> 3  a    3   30   60
#> 4  b    1   40   80
#> 5  b    2   50  100
#> 6  b    3   60  120
#> 7  c    1   70  140
#> 8  c    2   80  160
#> 9  c    3   90  180

dat %>% 
  group_by(ID) %>% 
  summarise(sum_val1 = sum(Val1, na.rm = TRUE),
            mean_val2 = mean(Val2, na.rm = TRUE)) %>%
  ungroup()

#> # A tibble: 3 x 3
#>   ID    sum_val1 mean_val2
#>   <fct>    <dbl>     <dbl>
#> 1 a           60        40
#> 2 b          150       100
#> 3 c          240       160

Создано в 2018-04-30 пакетом представ (v0.2.0).

...