R中使用case_when批量条件修改变量遇错,求解决方案
需要基于自定义函数创建30余个变量,其中N、B、C、Q均为数据框df中的变量列表。附上示例数据、函数代码及报错信息:
示例数据
record_id timeframe ... 95 2 0 0 94 2 1 NA 19 6 0 1 17 6 1 NA 18 6 2 NA 75 9 0 1 73 9 1 0 74 9 2 NA
自定义函数及调用
lag_vars <- function(df, N, B, C, Q){ df <- df %>% group_by(record_id) %>% mutate(N = case_when( timeframe == 0 ~ B, timeframe > 0 & C == 1 ~ Q, timeframe > 0 & C == 0 ~ lag(N) )) return(df) } lag_vars(t, Nt, Bt, Ct, Qt)
错误信息
Error in
mutate():
! Problem while computingN = case_when(...).
ℹ The error occurred in group 1: record_id = 2.
Caused by error incase_when():
!timeframe == 0 ~ B,timeframe > 0 & C == 1 ~ Q,timeframe > 0 & C == 0 ~ lag(N)must be length 2 or one, not 3.
Runrlang::last_trace()to see where the error occurred.
Called from: signal_abort(cnd, .file)
Warning messages:
1: Problem while computingN = case_when(...).
ℹ longer object length is not a multiple of shorter object length
ℹ The warning occurred in group 1: record_id = 2.
2: Problem while computingN = case_when(...).
ℹ longer object length is not a multiple of shorter object length
ℹ The warning occurred in group 1: record_id = 2.
疑问:case_when能否使用向量?或者能否将case_when嵌套在其他函数中解决该问题?
错误原因分析
- 变量列表处理错误:直接将
Nt、Bt等变量名向量传入函数,case_when中引用的B、Q是整个变量列表的向量,而分组内的行数(如record_id=2只有2行)与向量长度不匹配,导致报错。 - 非标准求值问题:函数中直接使用
N、B等符号,无法正确映射到数据框中的变量列表。
修正方案
case_when本身完全支持向量运算,问题出在批量处理多变量的逻辑上。可以通过tidyeval语法结合批量遍历函数来解决:
步骤1:编写单个变量处理函数
先实现处理一组N、B、C、Q变量的逻辑,确保分组内的计算正确:
library(dplyr) library(purrr) # 处理单个变量组的函数 lag_single_var <- function(df, N_col, B_col, C_col, Q_col) { df %>% group_by(record_id) %>% arrange(timeframe, .by_group = TRUE) %>% # 确保每个分组内按timeframe排序 mutate( !!N_col := case_when( timeframe == 0 ~ .data[[B_col]], timeframe > 0 & .data[[C_col]] == 1 ~ .data[[Q_col]], timeframe > 0 & .data[[C_col]] == 0 ~ lag(.data[[N_col]]) ) ) %>% ungroup() }
!!N_col:用tidyeval语法将变量名作为列名赋值.data[[B_col]]:通过字符串引用数据框中的列,避免非标准求值冲突arrange:确保每个分组内的timeframe按顺序排列,保证lag能正确取上一个时间点的值
步骤2:批量处理所有变量组
使用pmap遍历Nt、Bt、Ct、Qt四个变量列表,逐个处理后合并结果:
# 假设Nt、Bt、Ct、Qt是长度相同的变量名字符向量,例如: # Nt <- c("n_var1", "n_var2", ...) # Bt <- c("b_var1", "b_var2", ...) # 批量处理并合并结果 df_processed <- pmap(list(Nt, Bt, Ct, Qt), ~ lag_single_var(df = t, ..1, ..2, ..3, ..4)) %>% reduce(left_join, by = c("record_id", "timeframe"))
pmap:按位置匹配四个列表中的元素,逐个传入lag_single_varreduce(left_join):将所有处理后的结果按record_id和timeframe合并,得到最终的数据框
关键说明
case_when支持向量:每个条件和结果都可以是向量,只要长度与当前分组(或整个数据框)的行数匹配即可。- 批量处理多变量:通过遍历变量列表+tidyeval语法,避免直接传入整个向量导致的长度不匹配问题。
内容的提问来源于stack exchange,提问作者Jeremy B

