在数据框的条目中使用ifelse函数插入单个字符

编程语言 2026-07-07

我有一个数据框,想要修改条目,确保末尾的数字指示符为两位数,即使记录的数字在1 到9 之间。为了说明,起初是这样的:

data <- data.frame(
  V1 = c(1, 2, 3, NA, NA, NA, 4),
  V2 = c("ABC", "BCD", "CDE", "AB12", "AB5", "AB3", "DEF")
)

num <- as.character(c(0, 1, 2, 3, 4, 5, 6, 7, 8, 9))
new_data <- data %>%
  mutate(V2 = ifelse (
    is.na(V1),
    ifelse(
      str_sub(data$V2, -2, -2) %in% num,
      data$V2,
      str_sub(data$V2, -2, -3) <- 0
    ),
    data$V2
  ))

最终我希望数据框的样子是这样的:

ideal_data <- data.frame(  
    V1 = c(1, 2, 3, NA, NA, NA, 4),  
    V2 = c("ABC", "BCD", "CDE", "AB12", "AB05", "AB03", "DEF")
)

这是我尝试过的方法:

我的假设是,这会通过检查 V1 是否存在NA来改变列 V2,如果没有NA,就保持原样;如果有NA,就检查倒数第二个字符是否包含在 num 中。如果是这种情况,就保留它;如果不是,则在该位置补一个零。

然而,实际产生的是下面的数据框:

> new_data
  V1   V2
1  1 A0BC
2  2 B0CD
3  3 C0DE
4 NA AB12
5 NA    0
6 NA    0
7  4 D0EF

我到底哪里做错了?这个问题的解决方案是什么?

解决方案

你的误解在于 ifelse 的工作方式。ifelse 函数会对向量中每个元素(数据框的行)完整求值 testyesno 这三个参数,然后在 yesno 之间选择来生成结果。因此,当你在内部的 ifelse 中进行赋值时,它会把倒数第三个字符在每个实例中都替换为0(并非仅在匹配为 TRUE 的情形)。接着 <- 的返回值是 0,所以 no 变成了由 0 组成的向量,这些就被放到了 testFALSE 的位置。

核心信息是,不要在 ifelse 的参数里进行赋值。

如果你想按你的逻辑来做,那么最好逐行遍历,使用常规的 ifelse,而不是 ifelse 函数。也许比使用 str_sub 更好的是,使用正则表达式进行匹配与替换,使用 str_replace(或 sub 等)来实现。下面给出一个可能实现你需求的调用示例:

V2 <- c("ABC", "BCD", "CDE", "AB12", "AB5", "AB3", "DEF")
str_replace(V2, "([^0-9])([0-9])$", "\\10\\2")

这段代码是在查找一个非数字,紧接着一个数字,直到字符串的末尾。然后把匹配到的非数字、字面量 0 和匹配到的数字一起替换掉。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章