【问题标题】:R aggregate dynamically added columns with a separate function for each of themR聚合动态添加的列,每个列都有一个单独的函数
【发布时间】:2020-11-15 21:22:27
【问题描述】:

我有一个这样的数据框:

id  v    t1   t2  t3    t4   date1        list1

1   1.0  1.4   2   0.45   3    2020-09-03   val1
1   1.0  1.6   3   0.55  3.7  2020-09-05   val2

如何按id, v 分组并通过对每个列应用不同的聚合函数来聚合列t1, t2, t3, t4, date1, list1。更具体的

t1 -> mean
t2 -> max
t3 -> mean
t4 -> max
date -> max
list1 -> join as in python's ','.join

所以聚合后的框架看起来像:

id  v    t1   t2  t3    t4   date1        list1

1   1.0  1.5   3   0.5   3.7  2020-09-05   val1, val2

另外一件事是,这些列可以根据用户在 R 闪亮框架中的选择动态添加,这意味着我打算聚合的所有这些列都在数据框中,但其中一些可能不需要聚合,例如用户只能选择t1, date1 而不能选择其余的。因此,我的聚合参数取决于所选列,并且我确实可以从用户选择中获得列名。因此,如果我问如何构建动态聚合查询,这可能是有道理的。

在 python 中,我可以根据用户选择的列动态构建一个类似上面的字典,并使用类似pd.agg(**dict)的东西

如何在 R 中做到这一点?我试图查看 dplyr::summarise 和 data.table 但我似乎无法一次汇总所有这些。感谢您的帮助。

【问题讨论】:

  • 快速搜索了smartAgg,我自己没用过。

标签: r aggregate


【解决方案1】:

我们可以使用across 对列块应用函数

library(dplyr)
df1 %>% 
   group_by(id, v) %>% 
   summarise(across(c(t1, t3), mean),
             across(c(t2, t4, date1), max), 
             list1 = toString(list1), .groups = 'drop')

-输出

# A tibble: 1 x 8
#     id     v    t1    t3    t2    t4 date1      list1     
#  <int> <dbl> <dbl> <dbl> <int> <dbl> <chr>      <chr>     
#1     1     1   1.5   0.5     3   3.7 2020-09-05 val1, val2

如果函数、列名都是用户输入的

nm1 <- c("t1", "t3")
nm2 <- c("t2", "t4", "date1")
nm3 <- c("list1")

f1 <- "mean"
f2 <- "max"
f3 <- "toString"

df1 %>%
    group_by(id, v) %>%
    summarise(across(all_of(nm1), ~ match.fun(f1)(.)),
              across(all_of(nm2), ~ match.fun(f2)(.)),
              !! nm3 := match.fun(f3)(!! rlang::sym(nm3)), .groups = 'drop')

-输出

# A tibble: 1 x 8
#     id     v    t1    t3    t2    t4 date1      list1     
#  <int> <dbl> <dbl> <dbl> <int> <dbl> <date>     <chr>     
#1     1     1   1.5   0.5     3   3.7 2020-09-05 val1, val2

它也可以作为表达式传递并计算

expr1 <- glue::glue('across(c({toString(nm1)}), {f1});',
              'across(c({toString(nm2)}),  {f2});',
          'across(c({toString(nm3)}),  {f3})')
df1 %>% 
     group_by(id, v) %>%
     summarise(!!! rlang::parse_exprs(expr1), .groups = 'drop')

-输出

# A tibble: 1 x 8
#     id     v    t1    t3    t2    t4 date1      list1     
#  <int> <dbl> <dbl> <dbl> <int> <dbl> <date>     <chr>     
#1     1     1   1.5   0.5     3   3.7 2020-09-05 val1, val2

数据

df1 <- structure(list(id = c(1L, 1L), v = c(1, 1), t1 = c(1.4, 1.6), 
    t2 = 2:3, t3 = c(0.45, 0.55), t4 = c(3, 3.7), date1 = structure(c(18508, 
    18510), class = "Date"), list1 = c("val1", "val2")), row.names = c(NA, 
-2L), class = "data.frame")

【讨论】:

  • 谢谢。如何动态构建across 的参数,例如c(t1, t3)mean,因为这些列是由用户选择添加的,我不知道它们。
  • @SomeDude 我猜有一个选项可以让用户选择列名?我没有在您的帖子中找到该信息
  • 是的,我确实有来自用户选择的列名。但是我可以做across(c("user_selected_col1", "user_selected_col2"), "mean") 吗? across 是否接受列名和聚合函数的此类字符串?
  • @SomeDude 是的,确实如此。它可以接受不带引号的或带引号的或数字索引
  • 我试过这个:df1 %>% + group_by(id, v) %>% + summarise(across(c(t1, t3), "mean"), + cross(c(t2, t4, date1), "max"), + list1 = toString(list1), .groups = 'drop') ,但它给了我错误:错误:summarise() 输入问题..1。 x across() 输入 .fns 有问题。 i 输入 .fns 必须为 NULL、函数、公式或函数/公式列表。 i 输入..1across(c(t1, t3), "mean")。 i 错误发生在第 1 组:id = 1, v = 1。更不用说我没有提供 cols 为“t1”、“t2”等。
猜你喜欢
  • 2011-09-01
  • 2018-10-09
  • 2020-02-14
  • 2015-02-09
  • 1970-01-01
  • 2014-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多