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

多类型相似名称列中替换NA值并保留列类型的技术问题

问题与解决:保留列类型替换NA为对应类型的0

问题场景

我有一个数据集,包含多列名称相似但数据类型不同的字段,需要把所有NA值替换成0,同时必须保留各列的原有数据类型——因为后续还要给不同字符串分配其他数值。

示例数据集:

qdf = data.frame(bicep_wt = c("black band", "5", NA),
                 tricep_wt = c(2,NA,3))

尝试了两段代码替换NA,结果都报错:
代码1:

mutate(qdf, across(contains("wt"), ~case_when(is.numeric(.x) ~ tidyr::replace_na(., 0),
                                              is.character(.x) ~ tidyr::replace_na(., "0"))))

代码2:

mutate(qdf, across(contains("wt"), ~case_when(is.numeric(.x) ~ tidyr::replace_na(.x, 0),
                                              is.character(.x) ~ tidyr::replace_na(.x, "0"))))

错误信息:

Error in `mutate()`:
i In argument: `across(...)`.
Caused by error in `across()`:
! Can't compute column `bicep_wt`.
Caused by error in `case_when()`:
! Failed to evaluate the right-hand side of formula 1.
Caused by error in `vec_assign()`:
! Can't convert `replace` <double> to match type of `data` <character>.

错误原因

case_when的特性是会提前计算所有分支的表达式,然后统一返回类型。拿字符型的bicep_wt列来说,第一个分支is.numeric(.x)结果是FALSE,但R还是会先执行replace_na(.x, 0),这就试图把数值型的0塞进字符型列,直接触发类型不匹配的报错。

可行解决方案

放弃case_when,改用分支判断或者更贴合场景的函数:

方法1:用if/else分支判断列类型

library(dplyr)
library(tidyr)

qdf %>%
  mutate(across(contains("wt"), ~{
    if (is.numeric(.x)) {
      replace_na(.x, 0)
    } else if (is.character(.x)) {
      replace_na(.x, "0")
    } else {
      .x # 其他类型的列保持原样
    }
  }))

方法2:用coalesce简化代码

coalesce会直接返回第一个非NA值,结合类型判断动态生成替换值:

qdf %>%
  mutate(across(contains("wt"), ~coalesce(., if (is.numeric(.)) 0 else "0")))

方法3:基础replace函数实现

qdf %>%
  mutate(across(contains("wt"), ~{
    replace(., is.na(.), if (is.numeric(.)) 0 else "0")
  }))

最终结果

运行上述任一代码后,得到的结果如下,各列类型完全保留,NA被替换为对应类型的0:

bicep_wt tricep_wt
1 black band         2
2         5         0
3         0         3

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 20:23:08