使用dplyr的case_when替换多列中1为对应行id并将0转为NA
问题解决:dplyr中使用across+case_when替换值报错处理
问题背景
原始数据:
have <- structure(list(a1 = c(1, 1, 0, 1, 1, 1, 1, 1, 1, 1), a2 = c(1, 1, 0, 1, 1, 0, 1, 1, 1, 1), b1 = c(0, 0, 0, 0, 0, 1, 0, 0, 0, 0), b2 = c(1, 1, 0, 0, 0, 1, 0, 0, 0, 0), c1 = c(0, 0, 0, 0, 1, 0, 0, 0, 0, 0), c2 = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), id = 1:10), row.names = c(NA, -10L), class = c("tbl_df", "tbl", "data.frame"))
需求:将a1:c2变量中值为1的替换为对应行的id值,值为0的替换为NA_real_,要求使用dplyr和case_when实现。
尝试代码:
library(dplyr) want <- have %>% mutate(across(c(a1:c2), .fns = ~ case_when(. == 1 ~ id, T ~ NA_real_)) )
报错信息:
Error in `mutate()`: ! Problem while computing `..1 = across(c(a1:c2), .fns = ~case_when(. == 1 ~ id, T ~ NA_real_))`. Caused by error in `across()`: ! Problem while computing column `a1`. Caused by error in `` names(message) <- `*vtmp*` ``: ! 'names' attribute [1] must be the same length as the vector [0] Backtrace: 1. have %>% ... 8. dplyr::case_when(a1 == 1 ~ id, T ~ NA_real_) 9. dplyr:::replace_with(...) 10. dplyr:::check_type(val, x, name, error_call = error_call) 11. rlang::abort(msg, call = error_call) ... 16. rlang::cnd_message(c) 17. rlang:::cnd_message_format(cnd, ...) 18. rlang (local) cli_format(glue_escape(lines)) 19. rlang:::.rlang_cli_format(x, cli::format_error) 20. cli::cli_format(x, .envir = emptyenv())
错误原因
报错核心是类型不匹配:id是整数类型,而NA_real_是双精度数值类型,case_when要求所有分支的输出类型必须一致,类型冲突导致无法正常执行。
解决方案
将id转换为双精度数值类型,确保和NA_real_类型一致,修正后的代码如下:
library(dplyr) want <- have %>% mutate(across(a1:c2, ~ case_when(. == 1 ~ as.numeric(id), TRUE ~ NA_real_)) )
如果不需要严格使用case_when,也可以用更简洁的ifelse实现相同效果:
want <- have %>% mutate(across(a1:c2, ~ ifelse(. == 1, as.numeric(id), NA_real_)))
结果验证
运行修正后的代码,得到的结果与预期输出完全一致:
# 预期输出 want_expected <- structure(list(a1 = c(1, 2, NA, 4, 5, 6, 7, 8, 9, 10), a2 = c(1, 2, NA, 4, 5, NA, 7, 8, 9, 10), b1 = c(NA, NA, NA, NA, NA, 6, NA, NA, NA, NA), b2 = c(1, 2, NA, NA, NA, 6, NA, NA, NA, NA), c1 = c(NA, NA, NA, NA, 5, NA, NA, NA, NA, NA), c2 = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), id = 1:10), row.names = c(NA,-10L), class = c("tbl_df", "tbl", "data.frame")) # 检查是否一致 all.equal(want, want_expected) # [1] TRUE
内容的提问来源于stack exchange,提问作者LuizZ
相关产品推荐
相关产品推荐

