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

如何在R中不使用循环,连续在对应列旁添加新列?

批量添加分位数列并紧邻原变量列的实现方法

问题背景

我有如下DataFrame:

set.seed(42)  ## 保证结果可复现
df <- data.frame("time"=c(1:40), "Var1"=sample(1:100, size=40), 
                 "Var2"=sample(1:100, size=40), "Var3"=sample(1:100, size=40))
head(df)
#   time Var1 Var2 Var3
# 1    1   49    3   38
# 2    2   65   21    1
# 3    3   25    2   13
# 4    4   74   58   78
# 5    5   18   10    5
# 6    6  100   40   73

先计算各变量的分位数:

(quantiles <- as.data.frame(apply(df[2:4] , 2 , quantile, probs=seq(0, 1, 1/10), na.rm=TRUE)))
#       Var1 Var2  Var3
# 0%     2.0  2.0   1.0
# 10%    5.9  8.9  11.4
# 20%   19.6 17.6  15.8
# 30%   25.7 31.1  28.1
# 40%   35.2 41.2  35.8
# 50%   42.5 51.0  42.5
# 60%   53.2 57.4  56.4
# 70%   67.3 70.2  66.0
# 80%   80.8 80.4  78.6
# 90%   89.4 90.5  90.1
# 100% 100.0 99.0 100.0

接着为每个变量添加对应的分位数列,使用.bincode处理断点不唯一的情况:

df$QuantVar1 <- .bincode(x=df$Var1, breaks=quantiles$Var1, include.lowest=T, right=T)
df$QuantVar2 <- .bincode(x=df$Var2, breaks=quantiles$Var2, include.lowest=T, right=T)
df$QuantVar3 <- .bincode(x=df$Var3, breaks=quantiles$Var3, include.lowest=T, right=T)

head(df)
#   time Var1 Var2 Var3 QuantVar1 QuantVar2 QuantVar3
# 1    1   49    3   38         6         1         5
# 2    2   65   21    1         7         3         1
# 3    3   25    2   13         3         1         2
# 4    4   74   58   78         8         7         8
# 5    5   18   10    5         2         2         1
# 6    6  100   40   73        10         4         8

之后手动调整列顺序,让新列紧邻原变量:

library(dplyr); library(tidyft)

df <- df %>%
  relocate(QuantVar1, .after  = Var1)
df <- df %>%
  relocate(QuantVar2, .after  = Var2)
df <- df %>%
  relocate(QuantVar3, .after  = Var3)

head(df)
#   time Var1 QuantVar1 Var2 QuantVar2 Var3 QuantVar3
# 1    1   49         6    3         1   38         5
# 2    2   65         7   21         3    1         1
# 3    3   25         3    2         1   13         2
# 4    4   74         8   58         7   78         8
# 5    5   18         2   10         2    5         1
# 6    6  100        10   40         4   73         8

但变量数量多的时候手动操作不可行,希望用lapply系列函数实现,无需循环,同时让新列自动紧邻原变量列。


解决方案

方法1:使用dplyr的across+relocate批量处理

结合across批量生成分位数列,再通过构造列顺序规则自动重排,无需逐个调用relocate:

library(dplyr)

# 定义需要处理的变量列(排除time列)
var_cols <- names(df)[-1]

# 批量添加分位数列并调整顺序
df <- df %>%
  mutate(across(all_of(var_cols), 
                ~.bincode(x = ., breaks = quantiles[[cur_column()]], include.lowest = T, right = T),
                .names = "Quant{.col}")) %>%
  # 构造目标列顺序:time + 每个变量紧跟对应分位数列
  relocate(!!!unlist(map(var_cols, ~c(.x, paste0("Quant", .x)))), .after = time)

head(df)

方法2:使用purrr的map_dfc生成新列并合并

通过map_dfc对每个变量生成原列+分位数列的组合,再和time列合并:

library(purrr)
library(dplyr)

var_cols <- names(df)[-1]

# 对每个变量生成原列和分位数列的组合
var_quant_pairs <- map_dfc(var_cols, function(col) {
  tibble(
    !!col := df[[col]],
    !!paste0("Quant", col) := .bincode(df[[col]], breaks = quantiles[[col]], include.lowest = T, right = T)
  )
})

# 合并time列和生成的列对
df <- bind_cols(df[, "time", drop = F], var_quant_pairs)

head(df)

方法3:Base R实现(无需tidyverse)

利用lapply生成分位数列,再通过构造列索引重排:

var_cols <- names(df)[-1]

# 批量生成分位数列
quant_cols <- lapply(var_cols, function(col) {
  .bincode(df[[col]], breaks = quantiles[[col]], include.lowest = T, right = T)
})
names(quant_cols) <- paste0("Quant", var_cols)

# 添加到原数据框
df <- cbind(df, quant_cols)

# 构造目标列顺序:time + 每个变量和对应分位数列交替
new_col_order <- c("time", unlist(mapply(c, var_cols, paste0("Quant", var_cols))))
df <- df[, new_col_order]

head(df)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 07:15:32