如何在dplyr中基于过滤条件而非分组添加求和聚合列?
Great question! It’s totally reasonable to want cleaner, more readable code instead of chaining multiple mutate() calls with repeated sums. Let’s walk through some better alternatives, both within dplyr and beyond.
The most straightforward improvement is to consolidate all your aggregation logic into a single summarize() call. This makes your intent immediately clear to anyone reading the code:
library(dplyr) # One-step grouped summary of all required metrics summary_table <- df1 %>% group_by(country) %>% summarize( named_active = sum(assets[named == TRUE & active == 1]), named = sum(assets[named == TRUE]), TotalAssets = sum(assets) ) %>% ungroup() # Optional, if you don't need to keep the grouping summary_table
add_tally() If you love the convenience of add_count() but need sums instead of counts, dplyr::add_tally() is exactly what you’re looking for. Use the wt parameter to specify which variable to sum, and by to define your groups:
df1 %>% # Add total assets per country add_tally(assets, name = "TotalAssets", by = "country") %>% # Add total named assets per country add_tally(assets[named == TRUE], name = "named", by = "country") %>% # Filter to only named + active entries filter(named == TRUE, active == 1) %>% # Clean up column names and order select(country, named_active = assets, named, TotalAssets)
This mirrors the add_count() workflow perfectly, just swapping row counts for sums of your target variable.
ave() If you prefer sticking to base R, the ave() function can handle grouped conditional sums. It’s a bit more verbose, but no extra packages are needed:
# Calculate total assets per country df1$TotalAssets <- ave(df1$assets, df1$country, FUN = sum) # Calculate total named assets per country df1$named <- ave( df1$assets, df1$country, FUN = function(x) sum(x[df1$named[seq_along(x)] == TRUE]) ) # Calculate named + active assets per country df1$named_active <- ave( df1$assets, df1$country, FUN = function(x) sum(x[df1$named[seq_along(x)] == TRUE & df1$active[seq_along(x)] == 1]) ) # Filter and clean up the result result <- df1[df1$named == TRUE & df1$active == 1, c("country", "named_active", "named", "TotalAssets")] row.names(result) <- NULL # Reset row names for cleanliness result
data.table For large datasets or a more compact syntax, data.table offers an extremely clean way to do grouped conditional sums:
library(data.table) # Convert to data.table format setDT(df1) # Group and compute all metrics in one call result <- df1[, .( named_active = sum(assets[named == TRUE & active == 1]), named = sum(assets[named == TRUE]), TotalAssets = sum(assets) ), by = country] result
内容的提问来源于stack exchange,提问作者dad

