如何用dplyr/tidyr/purrr按行对数据框应用Hmisc::wtd.mean
使用dplyr/tidyr/purrr实现行级加权均值计算
我来帮你把现有的循环逻辑转换成tidyverse风格的实现,这里提供几种不同的思路,都能得到和你循环代码完全一致的结果,而且代码更简洁易维护:
方法1:用dplyr的rowwise() + c_across()(最直观)
这种方法最贴近你原来的循环逻辑,通过rowwise()告诉dplyr按行处理数据,c_across()可以快速选中指定列:
library(dplyr) library(Hmisc) # 基于你的原始数据框df进行计算 df <- df %>% rowwise() %>% mutate( weighted.means = wtd.mean( x = c_across(starts_with("mean")), # 选中所有以mean开头的列 weights = c_across(starts_with("weight")) # 选中所有以weight开头的列 ) ) %>% ungroup() # 取消按行分组,恢复常规数据框状态 # 验证结果和原循环一致 all.equal(df$weighted.means, c(70.74705, 82.85015, 82.40826, 73.35798, 70.02986, 74.05543, 73.64709, 77.12899, 72.56236, 84.74055)) # 输出TRUE
方法2:用purrr的pmap()(灵活的行级函数映射)
如果需要更灵活的行级操作,可以用pmap()来逐行传递参数给wtd.mean:
library(purrr) library(dplyr) library(stringr) library(Hmisc) df <- df %>% mutate( weighted.means = pmap_dbl(., function(...) { # 把当前行的所有列转换成列表 row_data <- list(...) # 提取mean和weight列的值 mean_vals <- unlist(row_data[str_detect(names(row_data), "^mean")]) weight_vals <- unlist(row_data[str_detect(names(row_data), "^weight")]) # 计算加权均值 wtd.mean(x = mean_vals, weights = weight_vals) }) )
或者更简洁的版本,先把mean和weight列打包成列表列,再用map2_dbl()映射:
df <- df %>% mutate( mean_list = pmap(list(.), ~ c_across(starts_with("mean"))), weight_list = pmap(list(.), ~ c_across(starts_with("weight"))), weighted.means = map2_dbl(mean_list, weight_list, ~ wtd.mean(.x, .y)) ) %>% select(-mean_list, -weight_list) # 移除中间生成的列表列
方法3:用tidyr重塑数据(适合多步骤行级分析)
如果后续还要对每行的mean和weight做更多处理,可以先把数据转成长格式,分组计算后再转回宽格式:
library(tidyr) library(dplyr) library(Hmisc) df <- df %>% mutate(row_id = row_number()) %>% # 添加行ID用于分组 pivot_longer( cols = -row_id, names_to = c(".value", "num"), # 拆分列名,.value表示保留的列类型(weight/mean) names_pattern = "(weight|mean)(\\d+)" # 正则匹配列名的前缀和数字 ) %>% group_by(row_id) %>% summarize(weighted.means = wtd.mean(mean, weights = weight)) %>% right_join(df, by = "row_id") %>% # 和原始数据合并 select(-row_id) # 移除行ID列
方法对比
- 方法1最直观,代码量最少,适合快速实现;
- 方法2灵活性最高,适合需要对每行数据做复杂预处理的场景;
- 方法3适合需要对每行的mean/weight对做额外分析(比如检查权重和是否为1)的场景。
内容的提问来源于stack exchange,提问作者Eric
相关产品推荐
相关产品推荐

