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
相关产品推荐
相关产品推荐

