You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用dplyr的across替代循环批量生成年度求和列?

问题:用dplyr高效生成年度行和汇总列

我需要用R的dplyr包,为数据集中的每个年度生成新列,新列的值是对应年度下季度末(Mar、Jun、Sep、Dec)各列的行求和结果。目前通过for循环可以实现需求,但希望找到更简洁高效的方案,比如使用across语句或map函数。

可复现示例代码

library(tidyverse)
library(glue)

# 创建示例数据集
set.seed(100) # 设置随机种子保证结果可复现
vars <- c("AgeGroup", paste0(month.abb[seq(3, 12, 3)], "_", rep(15:17, each = 4)))

(df <- cbind(LETTERS[1:5], matrix(rpois(n = (length(vars) - 1) * 5, 30), nrow = 5)) %>% 
    data.frame() %>%
    setNames(vars) %>% 
    tibble() %>% 
    mutate(across(-1, as.integer))
)

生成的数据集如下:

# A tibble: 5 × 13
  AgeGroup Mar_15 Jun_15 Sep_15 Dec_15 Mar_16 Jun_16 Sep_16 Dec_16 Mar_17 Jun_17 Sep_17 Dec_17
  <chr>     <int>  <int>  <int>  <int>  <int>  <int>  <int>  <int>  <int>  <int>  <int>  <int>
1 A            27     26     33     36     34     25     27     37     37     32     37     30
2 B            21     32     24     31     25     39     32     20     30     32     25     26
3 C            34     28     30     23     25     29     35     26     19     30     28     29
4 D            30     32     29     34     31     29     35     37     28     34     31     50
5 E            31     33     27     31     23     26     29     28     28     26     19     37

当前实现方式(for循环)

以下代码可以实现需求,但希望避免使用循环:

# 循环生成年度汇总列
for (i in 15:17) {
  df <- df %>% mutate("sum_{i}" := rowSums(across(ends_with(glue("_{i}")))))
}

# 查看结果
df %>% select(AgeGroup, starts_with("sum"))

优化方案

方案1:使用map_dfc生成汇总列后合并

利用purrr::map_dfc批量生成各年度的行和列,再与原数据集绑定,代码更简洁:

years <- 15:17

# 批量生成年度汇总列
sum_columns <- map_dfc(years, function(year) {
  df %>% transmute(!!paste0("sum_", year) := rowSums(across(ends_with(paste0("_", year)))))
})

# 合并到原数据集
df_final <- bind_cols(df, sum_columns)

方案2:长格式转换后计算再转宽

通过pivot_longer将数据转为长格式,按分组计算行和后再转回宽格式,最后与原数据合并,逻辑更清晰:

df_final <- df %>%
  # 转长格式,拆分月份和年份
  pivot_longer(-AgeGroup, names_to = c("month", "year"), names_sep = "_") %>%
  # 按AgeGroup和年份分组求和
  group_by(AgeGroup, year) %>%
  summarise(sum_val = sum(value), .groups = "drop") %>%
  # 转回宽格式,添加sum_前缀
  pivot_wider(names_from = year, values_from = sum_val, names_prefix = "sum_") %>%
  # 合并到原数据集
  left_join(df, .)

方案3:使用dplyr的across结合动态列名

利用across的动态选择和cur_column()提取年份,一次性生成所有汇总列:

df_final <- df %>%
  mutate(
    across(
      # 提取所有年度列的年份唯一值
      unique(str_extract(names(.)[-1], "_\\d+$")),
      ~ rowSums(across(ends_with(.x))),
      .names = "sum{str_remove(.col, '_')}"
    )
  )

以上三种方案都能替代for循环,实现高效生成年度行和汇总列的需求。


内容的提问来源于stack exchange,提问作者StatsStudent

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 12:41:35