如何在R语言中借助tidyverse基于年份对列进行条件求和?
使用tidyverse实现按年份条件求和生成累计列
问题背景
现有如下R数据框:
df <- data.frame( id = c(100023, 100024, 100034, 100064, 100054, 100032), year = c(1995, 1996, 1997, 1998, 1999, 2000), n_1995_point_count = c(10, 5, 3, 8, 2, 1), n_1996_point_count = c(7, 6, 2, 4, 3, 1), n_1997_point_count = c(3, 5, 1, 2, 6, 0), n_1998_point_count = c(8, 4, 9, 2, 1, 0), n_1999_point_count = c(3, 4, 9, 2, 2, 0), n_2000_point_count = c(5, 2, 3, 1, 4, 0) )
需要新增一列cumulative_sum,规则为:对每行,求和所有年份小于当前行year值的n_XXXX_point_count列(1995年无前置年份,累计和为0),最终输出如下:
id year n_1995_point_count n_1996_point_count n_1997_point_count n_1998_point_count n_1999_point_count n_2000_point_count cumulative_sum 1 100023 1995 10 7 3 8 3 5 0 2 100024 1996 5 6 5 4 4 2 5 3 100034 1997 3 2 1 9 9 3 5 4 100064 1998 8 4 2 2 2 1 14 5 100054 1999 2 3 6 1 2 4 12 6 100032 2000 1 1 0 0 0 0 2
解决方案(tidyverse语法)
方法一:行处理直接求和
通过行分组+列匹配的方式,直接逐行筛选符合条件的列并求和:
library(tidyverse) df_result <- df %>% rowwise() %>% mutate( cumulative_sum = sum( c_across(starts_with("n_")), .names_to = "col_year", .name_spec = ~ str_extract(., "\\d{4}") %>% as.integer(), .fns = ~ .x < year ) ) %>% ungroup() print(df_result)
代码说明
rowwise():将数据框按行分组,确保后续操作逐行执行c_across(starts_with("n_")):选中所有年份对应的点数列.name_spec:用正则表达式从列名中提取4位年份数字并转为整数.fns = ~ .x < year:筛选出年份小于当前行year的列,仅对这些列求和ungroup():取消行分组,恢复数据框常规结构
方法二:长格式转换后计算
先将宽格式转为长格式,计算累计和后再转回宽格式,逻辑更直观:
df_result2 <- df %>% pivot_longer( cols = starts_with("n_"), names_to = "year_col", values_to = "points" ) %>% mutate(year_col = str_extract(year_col, "\\d{4}") %>% as.integer()) %>% group_by(id) %>% mutate(cumulative_sum = sum(ifelse(year_col < year, points, 0))) %>% pivot_wider( names_from = year_col, names_prefix = "n_", names_suffix = "_point_count", values_from = points ) %>% ungroup() %>% select(names(df), cumulative_sum) print(df_result2)
代码说明
pivot_longer:将宽格式的年份列转为长格式,每行对应一个id、年份和点数- 提取列名中的年份数值后,按
id分组 - 对每个id下的行,判断年份是否符合条件,求和得到累计值
pivot_wider:转回宽格式并恢复原始列顺序
内容的提问来源于stack exchange,提问作者llamatrauma
相关产品推荐
相关产品推荐

