如何在R的tidyverse中按分组提取对应vt2的vo2值生成新列
问题:为R数据框添加对应分组的vt2的vo2值列
我知道这和之前的问题类似,但因涉及现有值,对我而言有所不同。以下是简化后的R数据框:
set.seed(2342) df <- tibble(bp = rep(c("vt1", "vt2"), 4), id = rep(c(1, 2), each = 4, 1), alg_vt1 = rep(c("a", "b"), each = 2, 2), alg_vt2 = rep(c("a", "b"), 4)) %>% mutate(vo2 = round(runif(nrow(.), 10, 20)), vo2 = if_else(bp == "vt2", vo2 * 2, vo2))
该数据框的样例如下:
bp id alg_vt1 alg_vt2 vo2 vt1 1 a a 18 vt2 1 a b 36 vt1 1 b a 16 vt2 1 b b 30 vt1 2 a a 19 vt2 2 a b 32 vt1 2 b a 10 vt2 2 b b 34
我希望生成一个新列vo2_vt2,其值为每个id、alg_vt1组合对应的vt2的vo2值,最终数据框应如下:
bp id alg_vt1 alg_vt2 vo2 vo2_vt2 vt1 1 a a 18 36 vt2 1 a b 36 36 vt1 1 b a 16 30 vt2 1 b b 30 30 vt1 2 a a 19 32 vt2 2 a b 32 32 vt1 2 b a 10 34 vt2 2 b b 34 34
我尝试过以下代码的多种变体,但后续内容要么报错,要么无法得到预期结果:
df %>% group_by(id, alg_vt1, alg_vt2) %>% mutate(vo2_vt2 =
我知道有一些临时解决方法,但肯定存在tidyverse的标准解法,我感觉可以用filter()或pick()实现,但无法整合起来。
解决方案
你之前的核心问题是分组维度错误,应该按id和alg_vt1分组(每个分组包含对应vt1和vt2的行),然后提取分组内bp == "vt2"的vo2值并广播到整个分组即可:
library(tidyverse) df %>% group_by(id, alg_vt1) %>% mutate(vo2_vt2 = vo2[bp == "vt2"]) %>% ungroup()
原理说明
- 按
id和alg_vt1分组后,每个分组内恰好包含一行bp == "vt2"的记录 vo2[bp == "vt2"]会提取该分组内vt2对应的vo2值,由于分组内的向量长度匹配,这个值会自动填充到分组内的所有行- 最后用
ungroup()取消分组,避免后续操作受分组影响
如果需要通过关联映射的方式实现,也可以用表连接的方法:
# 先提取vt2的vo2值作为映射表 vt2_map <- df %>% filter(bp == "vt2") %>% select(id, alg_vt1, vo2_vt2 = vo2) # 连接原表得到结果 df %>% left_join(vt2_map, by = c("id", "alg_vt1"))
两种方法都能得到你预期的结果,第一种更简洁高效。
内容的提问来源于stack exchange,提问作者a.hesse
相关产品推荐
相关产品推荐

