基于列标题字符筛选列并计算百分比差异的R语言实现
批量计算年度数据的百分比差异(基于dplyr/tidyverse)
需求背景
现有合并后的年度计数数据集,需按年份匹配对应列(如ABC_2019与ABC_DEF_2019_GHI),批量计算百分比差异,避免为每一年重复编写代码。计算公式为:差异百分比 = ((对比列 - 基准列)/基准列)*100
原始数据集
link_col <- c("A0001", "A0002", "A0003") ABC_2019 <- c(1000, 300, 5000) ABC_2020 <- c(800, 600, 2000) ABC_2021 <- c(600, 100, 900) ABC_DEF_2019_GHI <- c(1100, 400, 4800) ABC_DEF_2020_GHI <- c(900, 600, 2100) ABC_DEF_2021_GHI <- c(500, 200, 800) data <- data.frame(link_col, ABC_2019, ABC_2020, ABC_2021, ABC_DEF_2019_GHI, ABC_DEF_2020_GHI, ABC_DEF_2021_GHI)
解决方案
方法1:数据重塑法(灵活适配多年份场景)
通过将宽格式数据转为长格式,统一计算后再转回宽格式,适合年份较多的情况:
library(tidyverse) # 转长格式,提取分组与年份 data_long <- data %>% pivot_longer( cols = -link_col, names_to = c("group", "year"), names_pattern = "(.*)_(20\\d{2})_?", # 正则表达式匹配分组前缀与年份 values_to = "value" ) %>% # 转回宽格式,将同一分组的年度数据放在同一列 pivot_wider(names_from = group, values_from = value) %>% # 计算百分比差异 mutate(diff = ((ABC_DEF_GHI - ABC)/ABC)*100) %>% # 再次转回宽格式,恢复原始列结构并添加差异列 pivot_wider( names_from = year, values_from = c(ABC, ABC_DEF_GHI, diff), names_glue = "{.value}_{year}" ) # 合并原始数据与差异列(或直接使用data_long结果,已包含所有列) final_data <- data %>% left_join(data_long %>% select(link_col, starts_with("diff_")), by = "link_col") print(final_data)
方法2:宽格式直接计算法(适合少量年份场景)
直接在宽格式下通过年份匹配批量计算,代码更简洁:
library(tidyverse) # 提取所有年份 years <- unique(str_extract(names(data), "20\\d{2}")) %>% na.omit() # 批量生成差异列 data_final <- data %>% mutate( across( all_of(years), ~ ((get(paste0("ABC_DEF_", .x, "_GHI")) - get(paste0("ABC_", .x)))/get(paste0("ABC_", .x)))*100, .names = "diff_{.col}" ) ) print(data_final)
列标题筛选技巧
在dplyr中可通过以下方式快速筛选列:
starts_with("ABC_"):筛选所有以ABC_开头的列ends_with("_GHI"):筛选所有以_GHI结尾的列contains("2019"):筛选所有包含2019的列matches("20\\d{2}"):用正则表达式筛选所有年度列(匹配20xx格式)all_of(years):传入年份向量,精准匹配对应列
内容的提问来源于stack exchange,提问作者Rlearn
相关产品推荐
相关产品推荐

