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

如何用dplyr的mutate_at对成对列执行需多参数的函数?

当然可以实现这个需求!不过用mutate_at(或者现在更推荐的across())的时候,需要通过列名关联的方式,把每一组的_1列和对应的_2列配对起来——你之前的尝试之所以失败,是因为没法直接在funs里把x_1对应到x_2、y_1对应到y_2,得用字符串处理来动态找到对应列。

先拿你的示例数据来演示:

library(dplyr)

df <- data.frame( 
  x_1 = c(1, NA, 3), 
  x_2 = c(1, 2, 4), 
  y_1 = c(NA, 2, 1), 
  y_2 = c(5, 6, 7) 
)

方法1:用dplyr最新的across()语法(推荐)

across()是dplyr 1.0.0之后替代mutate_at的函数,更灵活直观:

result <- df %>%
  mutate(
    # 针对所有以_1结尾的列处理
    across(ends_with("_1"), 
           # 动态找到对应的_2列:把当前列名的_1换成_2,用get()获取该列的值
           ~ ifelse(is.na(.), get(sub("_1", "_2", cur_column())), .),
           # 设置新列名:去掉原列名的_1后缀
           .names = "{sub('_1', '', .col)}")
  )

print(result)
#>   x_1 x_2 y_1 y_2 x y
#> 1   1   1  NA   5 1 5
#> 2  NA   2   2   6 2 2
#> 3   3   4   1   7 3 1

这里cur_column()会返回当前正在处理的列名(比如x_1),通过sub("_1", "_2", ...)把它转换成x_2,再用get()提取这个列的数值,就能完美配对每一组列了。

方法2:用旧版的mutate_at(兼容dplyr旧版本)

如果你还在使用dplyr 1.0.0之前的版本,可以用mutate_at配合重命名来实现:

result_old <- df %>%
  # 对所有_1结尾的列处理,生成带_new后缀的临时列
  mutate_at(vars(ends_with("_1")),
            funs(new = ifelse(is.na(.), get(sub("_1", "_2", cur_column())), .))) %>%
  # 把临时列的_1_new后缀去掉,得到最终的x、y列
  rename_at(vars(ends_with("_new")), ~ sub("_1_new", "", .))

方法3:转长格式处理(适合列数很多的场景)

如果你的数据集有成十上百组这样的列,转成长格式处理会更清晰,避免写复杂的列名匹配:

library(tidyr)

result_long <- df %>%
  # 把宽格式转成长格式,拆分列名为分组(x/y)和编号(1/2)
  pivot_longer(everything(), names_to = c("group", "num"), names_sep = "_") %>%
  # 转回宽格式,让每组的1和2列并排
  pivot_wider(names_from = num, values_from = value) %>%
  # 合并1和2列:如果1列是NA就用2列的值
  mutate(merged = ifelse(is.na(`1`), `2`, `1`)) %>%
  # 只保留分组和合并后的值,再转回宽格式
  select(group, merged) %>%
  pivot_wider(names_from = group, values_from = merged) %>%
  # 和原数据合并
  bind_cols(df, .)

简单总结一下:核心思路是通过列名字符串的替换,动态找到每一组对应的备用列,而不是直接在函数里硬编码列名——这样不管你有多少组列,都能一次性处理完成。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:40:41