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

R语言:按分组对数据框指定列执行均值差运算

按分组计算变量与组内均值的差值

我有如下R数据框:

df <- structure(list(id = c("2023-02-15_10-30-49", "2023-02-15_10-30-49", 
"2023-02-15_10-30-49", "2023-02-15_10-30-49", "2023-02-15_10-30-49", 
"2023-02-15_10-30-49", "2023-02-15_10-30-49", "2023-02-15_10-30-49", 
"2023-02-15_10-30-49", "2023-02-15_10-30-49", "2023-02-15_10-30-49", 
"2023-02-15_10-30-49", "2023-02-15_10-30-49", "2023-02-15_10-30-49", 
"2023-02-15_10-33-16", "2023-02-15_10-33-16", "2023-02-15_10-33-16", 
"2023-02-15_10-33-16", "2023-02-15_10-33-16", "2023-02-15_10-33-16", 
"2023-02-15_10-33-16", "2023-02-15_10-33-16", "2023-02-15_10-33-16", 
"2023-02-15_10-33-16", "2023-02-15_10-33-16", "2023-02-15_10-33-16", 
"2023-02-15_10-33-16", "2023-02-15_10-33-16", "2023-02-15_10-33-16", 
"2023-02-15_10-33-16", "2023-02-15_10-33-16", "2023-02-15_10-33-16", 
"2023-02-15_10-33-46", "2023-02-15_10-33-46", "2023-02-15_10-33-46", 
"2023-02-15_10-33-46", "2023-02-15_10-33-46", "2023-02-15_10-33-46", 
"2023-02-15_10-33-46", "2023-02-15_10-33-46", "2023-02-15_10-33-46", 
"2023-02-15_10-33-46", "2023-02-15_10-33-46", "2023-02-15_10-33-46"
), V3 = c(93051, 93052, 93053, 93054, 93055, 93056, 93057, 93058, 
93059, 93100, 93101, 93102, 93103, 93104, 93318, 93319, 93320, 
93321, 93322, 93323, 93324, 93325, 93326, 93327, 93328, 93329, 
93330, 93331, 93332, 93333, 93334, 93335, 93348, 93349, 93350, 
93351, 93352, 93353, 93354, 93355, 93356, 93357, 93358, 93359
), V4 = c(5019.00214, 5019.00215, 5019.00216, 5019.00217, 5019.00218, 
5019.00214, 5019.00215, 5019.00215, 5019.00215, 5019.00215, 5019.00215, 
5019.00215, 5019.00214, 5019.00214, 5019.00198, 5019.00194, 5019.00193, 
5019.00193, 5019.00216, 5019.00194, 5019.00194, 5019.00194, 5019.00194, 
5019.00194, 5019.00194, 5019.00194, 5019.00194, 5019.00194, 5019.00194, 
5019.00195, 5019.00195, 5019.00195, 5019.00175, 5019.00175, 5019.00175, 
5019.00175, 5019.00175, 5019.00174, 5019.00175, 5019.00175, 5019.00175, 
5019.00174, 5019.00173, 5019.00173), V6 = c(500.86491, 500.86495, 
500.86497, 500.86498, 500.86499, 500.86375, 500.86374, 500.86372, 
500.86372, 500.86372, 500.86373, 500.86372, 500.86373, 500.86372, 
500.86428, 500.86419, 500.86421, 500.86423, 500.86392, 500.86343, 
500.86341, 500.86341, 500.86342, 500.86342, 500.86342, 500.86342, 
500.86342, 500.86342, 500.86342, 500.86344, 500.86343, 500.86343, 
500.86318, 500.86319, 500.86318, 500.86318, 500.86318, 500.86318, 
500.86315, 500.86315, 500.86315, 500.86315, 500.86313, 500.86312
), V8 = c(235.314, 235.423, 235.502, 235.556, 235.606, 230.496, 
230.502, 230.561, 230.556, 230.553, 230.564, 230.555, 230.59, 
230.598, 233.154, 233.162, 233.155, 233.142, 230.303, 230.491, 
230.464, 230.457, 230.466, 230.474, 230.472, 230.482, 230.479, 
230.476, 230.488, 230.496, 230.497, 230.499, 230.518, 230.525, 
230.514, 230.515, 230.531, 230.539, 230.507, 230.506, 230.509, 
230.513, 230.502, 230.486), V10 = c(0.38, 0.37, 0.37, 0.37, 0.36, 
0.037, 0.025, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 0.014, 
0.37, 0.37, 0.37, 0.37, 1.2, 0.014, 0.014, 0.014, 0.014, 0.014, 
0.014, 0.014, 0.015, 0.015, 0.014, 0.014, 0.014, 0.014, 0.016, 
0.018, 0.018, 0.019, 0.021, 0.098, 0.015, 0.014, 0.014, 0.014, 
0.014, 0.014), V11 = c(0.75, 0.73, 0.71, 0.7, 0.69, 0.056, 0.04, 
0.017, 0.015, 0.015, 0.015, 0.015, 0.014, 0.015, 0.6, 0.6, 0.6, 
0.6, 0.82, 0.017, 0.017, 0.019, 0.021, 0.021, 0.022, 0.022, 0.024, 
0.023, 0.021, 0.019, 0.018, 0.019, 0.023, 0.026, 0.028, 0.029, 
0.035, 0.15, 0.024, 0.022, 0.021, 0.019, 0.02, 0.022)), class = "data.frame", row.names = c(NA, 
-44L))

我需要按id分组,对V4至V11列的每个观测值,计算其与组内均值的差值。一开始尝试以下代码无法运行:

df %>% group_split(id) %>% map(~ mutate(., across(c("V4":"V11"), ~. - mean(.))))

编辑说明:重启R会话后,上述代码可正常执行,无实际问题。但考虑到相关解答对其他用户有参考价值,故保留该问题。


可行解决方案

方案1:直接分组计算(无需拆分数据框)

使用group_by替代group_split,语法更简洁,还能避免拆分后合并的步骤:

library(dplyr)

df_centered <- df %>%
  group_by(id) %>%
  mutate(across(V4:V11, ~ .x - mean(.x, na.rm = TRUE))) %>%
  ungroup()

添加na.rm = TRUE是为了兼容存在缺失值的场景,让代码更健壮。

方案2:原代码优化(拆分后合并)

如果坚持使用group_split+map的逻辑,计算完成后可以用bind_rows合并回单个数据框:

library(dplyr)
library(purrr)

df_centered <- df %>%
  group_split(id) %>%
  map(~ mutate(., across(V4:V11, ~ .x - mean(.x)))) %>%
  bind_rows()

方案3:data.table实现(高效处理大数据)

如果数据量较大,data.table的语法运行效率更高:

library(data.table)

setDT(df)
# 直接替换原列
df_centered <- df[, lapply(.SD, function(x) x - mean(x)), by = id, .SDcols = V4:V11]

# 若需要保留原列,新增中心化后的列
# df[, paste0(colnames(df)[4:11], "_centered") := lapply(.SD, function(x) x - mean(x)), by = id, .SDcols = V4:V11]

内容的提问来源于stack exchange,提问作者C. Guff

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 00:07:35