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

R语言mutate中case_when函数报错问题排查与修复

问题分析与修复方案

问题背景

现有result数据框结构如下:

MANUAL.IDAUTO.IDloc
NAPYPPYPL2
PIPpipNAL1
BarbarNAL5
NAPippipL3
NAPippip,BerBarL3

需将不同形式的标签替换为标准形式,依赖tesaurus词表(tag_id为待替换标签,tag_ok为标准标签):

tag_idtag_ok
PYPPYPPippip
PIPpipPippip
PippipPippip
BarbarBarbar

编写的R代码运行报错,错误信息如下:

Error in `mutate()`:
ℹ In argument: `AUTO.ID = (structure(function (..., .x = ..1, .y = ..2, . = ..1) ...`.
Caused by error in `case_when()`:
! Can't combine `..1 (right)` <character> and `..161 (right)` <double>.
---
Backtrace:
     ▆
  1. ├─result %>% ...
  2. ├─dplyr::mutate_at(...)
  3. │ ├─dplyr::mutate(.tbl, !!!funs)
  4. │ └─dplyr:::mutate.data.frame(.tbl, !!!funs)
  5. │   └─dplyr:::mutate_cols(.data, dplyr_quosures(...), by)
  6. │     ├─base::withCallingHandlers(...)
  7. │     └─dplyr:::mutate_col(dots[[i]], data, mask, new_columns)
  8. │       └─mask$eval_all_mutate(quo)
  9. │         └─dplyr (local) eval()
 10. ├─`<inln_cl_>`(AUTO.ID)
 11. │ └─rlang::eval_bare(`_quo`, base::parent.frame())
 12. ├─rlang (local) case_when(...)
 13. └─dplyr::case_when(...)

错误原因

  • 类型不兼容:case_when要求所有分支返回的数据类型一致,报错显示部分分支返回字符型、部分返回数值型,大概率是tesaurus的tag_ok列混入了数值类型,或生成的表达式中某条规则的tag_ok未被正确转义为字符。
  • 多标签匹配失效:原代码用str_detect匹配整个字符串,无法处理AUTO.ID中用逗号分隔的多标签(如Pippip,BerBar)。
  • 语法兼容性问题:mutate_at属于dplyr旧版语法,且通过as.formula拼接case_when表达式的方式易出现语法错误,若tag_id包含正则特殊字符(如.、*),会直接导致匹配失效。

修复方案

方法一:兼容单/多标签的通用替换(推荐)

利用stringr::str_replace_all结合命名向量实现批量替换,同时支持多标签场景:

library(dplyr)
library(stringr)
library(openxlsx)

# 读取并整理词表:生成忽略大小写的正则规则,去重避免重复替换
tesaurus <- read.xlsx("Requested_files/sp_tesaurus.xlsx", sheet = "tesaurus") %>%
  select(tag_id, tag_ok) %>%
  # 转义正则特殊字符,添加单词边界避免部分匹配
  mutate(tag_regex = str_c("\\b", str_replace_all(tag_id, regex("([.+*?^$(){}|\\[\\]\\\\])"), "\\\\\\1"), "\\b")) %>%
  distinct(tag_regex, tag_ok, .keep_all = TRUE)

# 构建命名向量:键为正则表达式,值为标准标签
replace_rules <- set_names(tesaurus$tag_ok, tesaurus$tag_regex)

# 对所有含ID的列执行替换,忽略大小写
result <- result %>%
  mutate(across(contains("ID"), ~ str_replace_all(., regex(names(replace_rules), ignore_case = TRUE), replace_rules)))

方法二:修正原case_when逻辑(仅适用于单标签)

若仅处理单标签场景,可修正原代码的类型与语法问题:

library(dplyr)
library(stringr)
library(openxlsx)

tesaurus <- read.xlsx("Requested_files/sp_tesaurus.xlsx", sheet = "tesaurus") %>%
  select(tag_id, tag_ok) %>%
  # 强制转换tag_ok为字符型,避免类型冲突
  mutate(tag_ok = as.character(tag_ok))

# 生成case_when规则字符串,转义特殊字符与单引号
case_rules <- paste(
  sprintf("str_detect(., regex('%s', ignore_case = TRUE)) ~ '%s'",
          str_replace_all(tesaurus$tag_id, regex("(['\\\\])"), "\\\\\\1"),
          str_replace_all(tesaurus$tag_ok, "'", "''")),
  collapse = ", "
)

case_expr <- as.formula(paste0("~ case_when(", case_rules, ", TRUE ~ as.character(.))"))

# 使用新版across替代mutate_at
result <- result %>%
  mutate(across(contains("ID"), case_expr))

关键说明

  • 正则中的\\b用于匹配完整单词,避免部分匹配(如防止把Barbarian中的Barbar误替换)。
  • 转义tag_id中的正则特殊字符,防止匹配逻辑出错。
  • across是dplyr新版语法,替代旧版mutate_at,兼容性与可读性更强。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 18:35:04