I am trying to write a function that takes a tibble and a list of filter specifications and performs a conditional summarize based on those filter specifications.
# Sample DF with a column to summarize and 2 ID columns.
df <- tibble(
to_summarize = c(1, 2, 8, 9),
ID1 = c('A', 'A', 'C', 'A'),
ID2 = c('X', 'Y', 'Z', 'X')
)
We can conditionally summarize using both IDs (returns 10), or using 1 ID (returns 12).
df %>%
summarize(
total1 = sum(to_summarize[ID1 == 'A' & ID2 == 'X']),
total2 = sum(to_summarize[ID1 == 'A'])
)
I want to allow the same flexibility within a function. The user should be able to provide a list of filters or an empty list (where the summarize function would execute on the entire column, with no filtering).
I imagine the easiest way being with a named list, where each name is a column to filter on, and each value is the value to filter that column on.
filters <- list(
ID1 = 'A',
ID2 = 'X'
)
# Here is my attempt at a function to implement this:
summarise_and_filter <- function(df, filters) {
df %>%
summarise(
total = sum(to_summarize[names(filters) == unname(unlist(filters))]))
}
# It does not work, it just returns zero
df %>%
summarise_and_filter(
filters = filters
)
# I imagine the function might need to call map in some way, or perhaps imap?
map_summarise_and_filter <- function(df, filters) {
df %>%
summarise(
total = sum(
to_summarize[
imap_lgl(
filters,
~.y == .x
)]
)
)
}
# But this also returns zero
df %>%
map_summarise_and_filter(
filters = filters
)
There are two operations done and one of them can be dynamically calculated
library(dplyr)
df %>%
mutate(total2 = sum(to_summarize[ID1 == filters[['ID1']]])) %>%
filter(across(starts_with("ID"), ~ . ==
filters[[cur_column()]])) %>%
summarise(total1 = sum(to_summarize),total2 = first(total2))
-output
# A tibble: 1 x 2
total1 total2
<dbl> <dbl>
1 10 12
If we want to do this without filter
, then reduce
the across
output to a single logical vector
to subset
library(purrr)
df %>%
summarise(total1 = sum(to_summarize[across(starts_with('ID'),
~ . == filters[[cur_column()]]) %>%
reduce(`&`)]),
total2 = sum(to_summarize[ID1 == filters[['ID1']]]))
-ouptut
# A tibble: 1 x 2
total1 total2
<dbl> <dbl>
1 10 12
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.