如何处理dplyr/across中数据框列数不匹配的报错问题
解决dplyr across列数不匹配的问题
问题出在across(contains("_2023"))返回2列,而across(contains("_2022"))返回3列,两者列数不等导致除法运算报错。要实现“无匹配列时返回NA”,可以用以下两种方法:
方法1:遍历2022指标并匹配2023列
直接针对每个2022年的指标,检查是否存在对应2023年列,存在则计算增长,不存在则返回NA:
library(tidyverse) raw_data_2 <- data.frame(category=c('A','B','C'), sales_2022=c(1,2,3), profit_2022=c(0.1,0.4,0.3), margin_2022=c(0.2,0.8,0.6), sales_2023=c(1.5,3,4), margin_2023=c(0.3,0.7,0.5) ) # 提取所有2022年的指标名称(去掉_2022后缀) metrics <- str_remove(names(raw_data_2)[str_detect(names(raw_data_2), "_2022")], "_2022") # 计算各指标的增长,无2023列则返回NA raw_data_2 %>% mutate( across(all_of(metrics), ~ { col_2023 <- paste0(cur_column(), "_2023") if (col_2023 %in% names(raw_data_2)) { (!!sym(col_2023) / .x) - 1 } else { NA_real_ } }, .names = "{col}_increase") )
运行后会生成sales_increase、profit_increase(全为NA)、margin_increase三列,符合需求。
方法2:转成长格式处理(更直观)
通过tidyr的pivot函数将数据转成长格式,统一计算增长后再转回宽格式,自动处理缺失列:
raw_data_2 %>% # 转成长格式,拆分指标和年份 pivot_longer(-category, names_to = c("metric", "year"), names_pattern = "(.*)_(\\d{4})") %>% # 转回宽格式,按指标分2022和2023列 pivot_wider(names_from = year, values_from = value) %>% # 计算增长值,无2023列则自动为NA mutate(increase = (`2023` / `2022`) - 1) %>% # 转回原宽格式,生成各指标的增长列 pivot_wider(names_from = metric, values_from = c(`2022`, `2023`, increase), names_glue = "{metric}_{.value}") %>% # 调整增长列的名称(去掉_increase后缀) rename_with(~ str_remove(., "_increase"), ends_with("_increase"))
这种方法更适合指标较多的场景,无需手动提取指标列表,自动适配所有存在的2022指标。
内容的提问来源于stack exchange,提问作者anderwyang
相关产品推荐
相关产品推荐

