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

如何基于变量名动态创建case_when()表达式实现批量年份匹配?

批量匹配收入变量与对应年份销售变量的高效实现

问题背景

现有包含多组收入变量(revenues_*)和销售变量(sales_*)的数据框,需要为每个收入变量生成对应的年份变量:当收入变量的值与某年份的销售变量值匹配时,返回该年份,否则返回NA。手动逐个编写case_when逻辑扩展性极差,需要高效的批量处理方案。

示例数据与预期效果

以下是简化示例及手动实现的预期逻辑(仅作效果参考,扩展性差):

library(tidyverse)
library(rlang)

# 创建示例数据框
df <- tibble(
  revenues_1 = c(1, 3, 4),
  revenues_2 = c(2, 4, 5),
  sales_2005 = c(1, 2, 3),
  sales_2006 = c(2, 3, 4),
  sales_2007 = c(3, 4, 5)
)

# 手动实现逻辑(仅作效果参考)
# df <- df %>% 
#   rowwise() %>%
#   mutate(
#     year_1 = case_when(
#       revenues_1 == sales_2005 ~ 2005,
#       revenues_1 == sales_2006 ~ 2006,
#       revenues_1 == sales_2007 ~ 2007,
#       .default = NA
#     ),
#     year_2 = case_when(
#       revenues_2 == sales_2005 ~ 2005,
#       revenues_2 == sales_2006 ~ 2006,
#       revenues_2 == sales_2007 ~ 2007,
#       .default = NA
#     )
#   ) %>%
#   ungroup()

无效尝试分析

你尝试的代码未生效的核心问题:生成的表达式中var == 'sales_2005'是将收入变量的值与**字符串sales_2005**比较,而非与数据框中sales_2005列的数值比较,逻辑完全错误。

# 你的无效尝试代码
# years_exprs <- map(2005:2007, ~parse_expr(paste0("var == 'sales_", .x, "' ~ ", .x)))
# 
# df <- df %>% 
#   rowwise() %>%
#   mutate(across(starts_with("revenues_"), function(var) {
#     case_when(
#       !!!years_exprs,
#       .default = NA
#     )
#   }, .names = "year_{.col}")) %>% 
#   ungroup()

两种高效批量实现方案

方案1:动态生成case_when表达式(宽格式处理)

通过rlang动态生成每个收入变量对应的匹配条件,无需转换数据格式,代码简洁高效:

# 提取销售列及对应年份
sales_cols <- str_subset(names(df), "^sales_")
years <- str_extract(sales_cols, "\\d+") %>% as.integer()

# 定义函数:为指定收入变量生成case_when表达式
generate_case_when <- function(rev_col) {
  # 逐个生成"收入列 == 销售列 ~ 年份"的条件表达式
  conditions <- map2(sales_cols, years, ~expr(!!sym(rev_col) == !!sym(.x) ~ .y))
  # 组合成完整的case_when表达式
  expr(case_when(!!!conditions, .default = NA))
}

# 批量处理所有收入变量
df_result <- df %>%
  mutate(across(
    starts_with("revenues_"), 
    ~eval_tidy(generate_case_when(cur_column())),
    # 重命名新变量:将revenues_X转为year_X
    .names = "year_{str_remove(.col, 'revenues_')}"
  ))

# 查看结果
df_result

运行后输出:

# A tibble: 3 × 7
  revenues_1 revenues_2 sales_2005 sales_2006 sales_2007 year_1 year_2
       <dbl>      <dbl>      <dbl>      <dbl>      <dbl>  <int>  <int>
1          1          2          1          2          3   2005   2006
2          3          4          2          3          4   2006   2007
3          4          5          3          4          5   2007   2007

方案2:长格式转换匹配(直观易维护)

通过将宽格式数据转为长格式,完成匹配后再转回宽格式,逻辑更直观,适合复杂匹配场景:

df_long_result <- df %>%
  # 收入列转长格式:保留ID、收入值
  pivot_longer(
    starts_with("revenues_"), 
    names_to = "rev_id", 
    values_to = "rev_value"
  ) %>%
  # 销售列转长格式:保留年份、销售值
  pivot_longer(
    starts_with("sales_"), 
    names_to = "sales_year", 
    values_to = "sales_value"
  ) %>%
  # 提取年份数字
  mutate(year = str_extract(sales_year, "\\d+") %>% as.integer()) %>%
  # 匹配收入值与销售值
  filter(rev_value == sales_value) %>%
  # 清理冗余列
  select(-sales_year, -sales_value) %>%
  # 转回宽格式:生成year_X列
  pivot_wider(
    names_from = rev_id, 
    values_from = year, 
    names_prefix = "year_"
  ) %>%
  # 与原数据合并
  bind_cols(df, .) %>%
  # 调整列顺序(可选)
  select(starts_with("revenues_"), starts_with("sales_"), starts_with("year_"))

# 查看结果
df_long_result

该方案输出与方案1完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 20:59:57