如何用R批量比较两组数据中同名成对列的数值差异?
批量计算两组数据对应列的绝对差异
我有两组来自组织主数据库的数据,数据获取与聚合方式略有差异,且无法查看原始查询语句。需要逐行逐列对比两组数据的计数差异。目前通过mutate手动实现可行,但实际数据列数众多,代码冗余且低技能使用者易出错。期望有一个不依赖列位置的基础函数来实现批量处理,示例数据如下:
library(tidyverse) eg_data1 <- data.frame( Group = c('RubberChickens', 'WhoopieCushions', 'FartSpray', 'Tupperware', 'Coffee', 'Bags', 'Scissors', 'Goodfellas'), Fall21 = c(1, 18, 38, 28, 34, 92, 34, 16) , Spring22 = c(29, 45, 23, 94, 23, 19, 20, 83) , Fall22 = c(26, 18, 87, 54, 96, 21, 57, 51) , Spring23 = c(58, 41, 54, 92, 71, 15, 51, 84) , Fall23 = c(12, 51, 49, 25, 63, 17, 80, 74)) eg_data2 <- data.frame( Group = c('RubberChickens', 'WhoopieCushions', 'FartSpray', 'Tupperware', 'Coffee', 'Bags', 'Scissors', 'Goodfellas'), Fall21 = c(1, 19, 34, 28, 33, 92, 34, 17) , Spring22 = c(29, 47, 23, 96, 21, 19, 20, 82) , Fall22 = c(24, 18, 86, 54, 99, 21, 53, 51) , Spring23 = c(58, 43, 54, 92, 79, 15, 53, 84) , Fall23 = c(13, 51, 45, 25, 66, 18, 81, 74))
方案1:用dplyr::across批量生成差异列
利用across可以批量匹配目标列,自动计算对应列的绝对差异,无需手动逐个定义:
eg_data3 <- eg_data1 %>% left_join(eg_data2, by = "Group") %>% mutate( # 匹配所有以Fall/Spring开头的.x列,计算与对应.y列的绝对差 across(starts_with(c("Fall", "Spring")), ~abs(.x - get(str_replace(cur_column(), "\\.x", "\\.y"))), .names = "Comp{col}" ) %>% # 去掉差异列名里的.x后缀 rename_with(~str_remove(., "\\.x"), starts_with("Comp")) ) # 查看差异列结果 select(eg_data3, Group, starts_with("Comp"))
关键逻辑说明:
starts_with(c("Fall", "Spring")):精准匹配需要对比的数值列(排除Group列)str_replace(cur_column(), "\\.x", "\\.y"):自动将当前.x列名替换为对应的.y列名.names = "Comp{col}":为新生成的差异列统一添加Comp前缀,后续用rename_with清理冗余后缀
方案2:宽转长再合并计算(更易理解)
如果觉得列名替换逻辑复杂,可先将数据转为长格式,合并后计算差异,再转回宽格式,逻辑更直观:
# 将两组数据转为长格式 long_data1 <- eg_data1 %>% pivot_longer(-Group, names_to = "Period", values_to = "Value1") long_data2 <- eg_data2 %>% pivot_longer(-Group, names_to = "Period", values_to = "Value2") # 合并数据并计算绝对差异 comp_data <- long_data1 %>% left_join(long_data2, by = c("Group", "Period")) %>% mutate(CompValue = abs(Value1 - Value2)) # 转回宽格式,还原原始列结构 eg_data3_wide <- comp_data %>% pivot_wider( names_from = Period, values_from = c(Value1, Value2, CompValue), names_glue = "{.value}{Period}" ) # 查看差异列结果 select(eg_data3_wide, Group, starts_with("CompValue"))
优势:
- 无需处理
.x/.y的列名后缀,步骤清晰 - 低技能使用者更容易理解数据转换的逻辑,出错概率更低
内容的提问来源于stack exchange,提问作者Adam_S
相关产品推荐
相关产品推荐

