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

如何用更简洁方式或dplyr实现数据框按n列分组的列除法运算?

问题描述

现有如下R语言数据框:

df <- data.frame(a = c(1,2,3,4), 
                 b = c(5,6,7,8), 
                 c = c(22,33,44,55), 
                 d = c(7,8,9,10), 
                 e = c(2,3,4,5), 
                 f = c(99,88,66,44))

输出结果:

a b  c  d e  f
1 1 5 22  7 2 99
2 2 6 33  8 3 88
3 3 7 44  9 4 66
4 4 8 55 10 5 44

需求:将每n列(示例中n=2)除以最初的n列,当前通过手动逐列赋值实现:

df$c <- df$c / df$a
df$d <- df$d / df$b
df$e <- df$e / df$a
df$f <- df$f / df$b
df$a <- df$a / df$a
df$b <- df$b / df$b

最终得到:

a b        c        d        e         f
1 1 1 22.00000 1.400000 2.000000 19.800000
2 1 1 16.50000 1.333333 1.500000 14.666667
3 1 1 14.66667 1.285714 1.333333  9.428571
4 1 1 13.75000 1.250000 1.250000  5.500000

询问是否存在更简洁的实现方式,或如何用dplyr包完成该操作?

解决方案

一、基础R简洁实现

通过循环+索引匹配的方式,避免手动逐列赋值:

n <- 2
# 提取前n列作为除数模板
div_template <- df[, 1:n]
# 遍历所有列,对应除以模板中的循环列
df[] <- lapply(seq_len(ncol(df)), function(col_idx) {
  df[, col_idx] / div_template[, (col_idx - 1) %% n + 1]
})

核心逻辑:

  • 先获取前n列作为重复使用的除数模板
  • 对每一列,用(col_idx - 1) %% n + 1计算它在模板中的对应位置(实现循环匹配)
  • 逐列完成除法后重新赋值给原数据框

二、dplyr包实现

利用across()函数结合列索引匹配,代码更简洁:

library(dplyr)

n <- 2
df <- df %>%
  mutate(across(everything(), ~ .x / pick((cur_column() %>% as.integer() - 1) %% n + 1)))

如果觉得列名转整数的写法不够直观,也可以用列索引直接处理:

df <- df %>%
  mutate(across(1:ncol(.), ~ .x / !!sym(names(.)[(cur_column() %>% as.integer() - 1) %% n + 1])))

逻辑说明:

  • across(everything())指定对所有列执行操作
  • cur_column()获取当前处理的列名,转为整数后计算对应的除数列位置
  • pick()或!!sym()提取对应的除数列,完成除法运算

上述两种方法的输出结果和手动赋值完全一致,且能灵活适配不同的n值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 15:35:51