如何将变量名传递给 dplyr 管道中的有条件求和?
How do I pass a variable name to conditionally sum in dplyr pipe?
问题的症结在于如何将列变量传入分组的df中,对数据进行条件求和。该示例的数据如下:
library(dplyr)
library(rlang)
set.seed(1)
# dummy dates
date_vars <- purrr::map(c('2018-01-31', '2018-02-28', '2018-03-31',
'2018-04-30', '2018-05-31', '2018-06-30',
'2018-07-31', '2018-08-31', '2018-09-30',
'2018-10-31', '2018-11-30', '2018-12-31'), as.Date) %>%
purrr::reduce(c)
dummy_df <- tibble(
id = rep(c("a", "b", "c"), each = 12),
date = rep(date_vars, 3),
value = runif(36, 1, 10)
)
下面的函数将采用一个数据框,按变量分组(使用 rlang 的 sym 函数),然后通过添加日期大于或等于某个日期期间的所有值来创建一个新的汇总列。在这里我总结了 3 个月的 'values'.
agg_by_period <- function(df, date_period, period, grouping, new_col_prefix){
grouping_vars <- syms(grouping)
new_sum_column <- quo_name(paste0(new_col_prefix, "sum_", period, 'm'))
df %>%
group_by(!!!grouping_vars) %>%
summarize(!!new_sum_column := sum(value[date >= date_period], na.rm = T)) %>%
select(!!!grouping_vars, !!sym(new_sum_column))
}
agg_by_period(df = dummy_df,
date_period = as.Date('2018-10-31'),
grouping = 'id',
period = 3,
new_col_prefix = 'new_'
)
# A tibble: 3 x 2
id new_sum_3m
<chr> <dbl>
1 a 7.00
2 b 11.9
3 c 18.1
太棒了!我的问题是特定于当此列的名称不是 "value" 时,使函数中的 'value' 动态化。我天真的尝试使用 sym() 传入此专栏,其错误如下:
agg_by_period2 <- function(df, date_period, period, grouping, new_col_prefix,
value_var){
grouping_vars <- syms(grouping)
new_sum_column = quo_name(paste0(new_col_prefix, "sum_", period, 'm'))
value_var_col <- sym(value_var)
df %>%
group_by(!!!grouping_vars) %>%
summarize(!!new_sum_column := sum(!!value_var_col[date >= date_period], na.rm = T)) %>%
select(!!!grouping_vars, !!sym(new_sum_column))
}
agg_by_period2(df = dummy_df,
date_period = as.Date('2018-10-31'),
grouping = 'id',
period = 3,
new_col_prefix = 'new_',
value_var = 'value'
)
Error in `>=.default`(date, date_period) :
comparison (5) is possible only for atomic and list types
上述函数将在删除日期条件 ([date >= date_period]) 时起作用。任何帮助将不胜感激。
这似乎是 !!
和 [
的操作顺序问题。看起来你只需要将拼接包裹在括号中
df %>%
group_by(!!!grouping_vars) %>%
summarize(!!new_sum_column := sum((!!value_var_col)[date >= date_period], na.rm = T)) %>%
select(!!!grouping_vars, !!sym(new_sum_column))
注意 (!!value_var_col)
而不仅仅是 !!value_var_col
。这样拼接将在子集化之前发生。
问题的症结在于如何将列变量传入分组的df中,对数据进行条件求和。该示例的数据如下:
library(dplyr)
library(rlang)
set.seed(1)
# dummy dates
date_vars <- purrr::map(c('2018-01-31', '2018-02-28', '2018-03-31',
'2018-04-30', '2018-05-31', '2018-06-30',
'2018-07-31', '2018-08-31', '2018-09-30',
'2018-10-31', '2018-11-30', '2018-12-31'), as.Date) %>%
purrr::reduce(c)
dummy_df <- tibble(
id = rep(c("a", "b", "c"), each = 12),
date = rep(date_vars, 3),
value = runif(36, 1, 10)
)
下面的函数将采用一个数据框,按变量分组(使用 rlang 的 sym 函数),然后通过添加日期大于或等于某个日期期间的所有值来创建一个新的汇总列。在这里我总结了 3 个月的 'values'.
agg_by_period <- function(df, date_period, period, grouping, new_col_prefix){
grouping_vars <- syms(grouping)
new_sum_column <- quo_name(paste0(new_col_prefix, "sum_", period, 'm'))
df %>%
group_by(!!!grouping_vars) %>%
summarize(!!new_sum_column := sum(value[date >= date_period], na.rm = T)) %>%
select(!!!grouping_vars, !!sym(new_sum_column))
}
agg_by_period(df = dummy_df,
date_period = as.Date('2018-10-31'),
grouping = 'id',
period = 3,
new_col_prefix = 'new_'
)
# A tibble: 3 x 2
id new_sum_3m
<chr> <dbl>
1 a 7.00
2 b 11.9
3 c 18.1
太棒了!我的问题是特定于当此列的名称不是 "value" 时,使函数中的 'value' 动态化。我天真的尝试使用 sym() 传入此专栏,其错误如下:
agg_by_period2 <- function(df, date_period, period, grouping, new_col_prefix,
value_var){
grouping_vars <- syms(grouping)
new_sum_column = quo_name(paste0(new_col_prefix, "sum_", period, 'm'))
value_var_col <- sym(value_var)
df %>%
group_by(!!!grouping_vars) %>%
summarize(!!new_sum_column := sum(!!value_var_col[date >= date_period], na.rm = T)) %>%
select(!!!grouping_vars, !!sym(new_sum_column))
}
agg_by_period2(df = dummy_df,
date_period = as.Date('2018-10-31'),
grouping = 'id',
period = 3,
new_col_prefix = 'new_',
value_var = 'value'
)
Error in `>=.default`(date, date_period) :
comparison (5) is possible only for atomic and list types
上述函数将在删除日期条件 ([date >= date_period]) 时起作用。任何帮助将不胜感激。
这似乎是 !!
和 [
的操作顺序问题。看起来你只需要将拼接包裹在括号中
df %>%
group_by(!!!grouping_vars) %>%
summarize(!!new_sum_column := sum((!!value_var_col)[date >= date_period], na.rm = T)) %>%
select(!!!grouping_vars, !!sym(new_sum_column))
注意 (!!value_var_col)
而不仅仅是 !!value_var_col
。这样拼接将在子集化之前发生。