能否在dplyr::case_when()中用for循环批量重编码向量?
批量生成case_when条件实现向量重编码
问题场景
你有一个包含N个命名元素的列表(实际元素超过20个),需要用它对现有向量进行重编码。手动编写case_when()的条件过于繁琐,尝试在case_when()中嵌入for循环的写法无法运行,需要批量生成条件的解决方案。
解决方案
case_when()无法直接嵌入for循环,因为它需要接收一系列条件 ~ 结果的表达式作为参数。可以通过表达式拼接或其他更高效的方法实现批量重编码:
方法1:用rlang+purrr批量生成case_when条件
利用purrr::imap遍历列表生成条件表达式,再通过rlang的非标准求值将表达式传入case_when():
library(dplyr) library(purrr) library(rlang) # 原数据定义 vowels <- c("a","e","i","u") consonants <- letters[!(letters %in% vowels)] signs <- c("!",".") Listelement <- list(vowels = vowels, consonants = consonants) OldVar <- c(vowels, consonants, "", "", signs) # 批量生成条件表达式:每个列表元素对应一个「值匹配 ~ 分类名」的表达式 case_conditions <- imap(Listelement, ~ expr(OldVar %in% !!.x ~ !!.y)) # 组合所有条件并执行重编码 NewVar <- case_when( OldVar == "" ~ "empty", !!!case_conditions, # 展开表达式列表 TRUE ~ "other" ) NewVar
方法2:用映射表简化重编码(无需case_when循环)
先将列表转换为「值-分类」的映射表,再通过匹配实现重编码,代码更简洁:
library(dplyr) # 将列表转换为值-分类映射数据框 map_df <- stack(Listelement) %>% rename(value = values, category = ind) # 执行重编码:空值优先处理,匹配不到的归为other NewVar <- ifelse(OldVar == "", "empty", map_df$category[match(OldVar, map_df$value)] %>% replace_na("other")) NewVar
方法3:用命名向量配合recode_factor
将列表转换为命名向量,再用recode_factor()实现批量映射:
library(dplyr) # 生成「值=分类名」的命名向量 recode_map <- setNames(rep(names(Listelement), lengths(Listelement)), unlist(Listelement)) # 执行重编码 NewVar <- case_when( OldVar == "" ~ "empty", TRUE ~ recode_factor(OldVar, !!!recode_map, .default = "other") ) NewVar
为什么原for循环写法失效?
case_when()要求参数是独立的条件 ~ 结果表达式,而for循环仅执行循环操作,不会返回可被case_when()识别的表达式集合,因此无法直接嵌入使用。
内容的提问来源于stack exchange,提问作者Volker Holzendorf
相关产品推荐
相关产品推荐

