为何在R语言的for循环中使用mutate()函数不生效?
问题:循环重编码变量无效果且无报错
我有一批变量(epds_1到epds_10),原本应该编码为0-3或NA,但当前编码为1-4,且用"."表示NA。尝试用for循环结合mutate()和case_when()重编码,但运行后数据未发生变化,也无报错信息。
转换前epds_1的分布:
tabyl(df$epds_1) # df$epds_1 n # . 6 # 1 472 # 2 93 # 3 45 # 4 23 # <NA> 10
使用的循环代码:
for (v in c("epds_1", "epds_2", "epds_3", "epds_4", "epds_5", "epds_6", "epds_7", "epds_8", "epds_9","epds_10")) { df <- df %>% mutate(`v` = case_when(`v` == "." ~ NA_real_, `v` == "1" ~ 0, `v` == "2" ~ 1, `v` == "3" ~ 2, `v` == "4" ~ 3)) }
期望结果(epds_1的NA计数合并为16):
tabyl(df$epds_1) # df$epds_1 n # 0 472 # 1 93 # 2 45 # 3 23 # <NA> 16
问题原因
代码中的mutate(v = ...)用反引号包裹了v,这会把它当成字面量列名——每次循环都在创建/覆盖名为v的列,而非修改目标变量epds_1等。同时case_when里的v也是字面量,没有引用循环中的变量值,自然不会对目标列做任何修改。
解决方案
方法1:修正for循环写法
用.data[[v]]引用循环变量对应的列,用!!sym(v)动态指定赋值的列名:
library(dplyr) for (v in c("epds_1", "epds_2", "epds_3", "epds_4", "epds_5", "epds_6", "epds_7", "epds_8", "epds_9","epds_10")) { df <- df %>% mutate(!!sym(v) := case_when( .data[[v]] == "." ~ NA_real_, .data[[v]] == "1" ~ 0, .data[[v]] == "2" ~ 1, .data[[v]] == "3" ~ 2, .data[[v]] == "4" ~ 3 )) }
!!sym(v):将字符串格式的变量名转换为dplyr可识别的变量引用,:=支持动态列名赋值;.data[[v]]:明确引用当前数据框中名为v的列。
方法2:用across()批量处理(更简洁)
无需循环,用across()一次性处理所有目标变量,代码更简洁:
df <- df %>% mutate(across(starts_with("epds_"), ~ case_when( .x == "." ~ NA_real_, .x == "1" ~ 0, .x == "2" ~ 1, .x == "3" ~ 2, .x == "4" ~ 3 )))
starts_with("epds_"):匹配所有以epds_开头的变量,也可以直接列出变量名c("epds_1", ..., "epds_10");.x:代表当前正在处理的列,across()会自动遍历所有匹配变量完成重编码。
运行上述任意一种方案后,用tabyl(df$epds_1)即可验证得到期望的结果。
内容的提问来源于stack exchange,提问作者citychrisp
相关产品推荐
相关产品推荐

