R语言dplyr mutate()操作中如何访问其他行匹配取值
问题背景
现有R语言tibble格式数据集ipTraceSummary2,共11839行6个字段,样例结构如下:
> ipTraceSummary2 # A tibble: 11,839 × 6 DstPo Protocol IntervalStart n intervalLength rate <int> <chr> <chr> <int> <dbl> <dbl> 1 23 TCP 15:31:00 7 10 0.7 2 23 TCP 15:31:10 4 10 0.4 3 23 TCP 15:31:20 5 10 0.5 4 23 TCP 15:31:30 3 10 0.3 5 23 TCP 15:31:40 5 10 0.5 6 23 TCP 15:31:50 4 10 0.4 7 23 TCP Post 26 39.5 0.658 8 23 TCP Pre 37 60.0 0.617 9 23 TELNET 15:31:00 6 10 0.6 10 23 TELNET 15:31:10 4 10 0.4 # … with 11,829 more rows
需求是为数据集新增baseline列,列值规则:和当前行DstPo、Protocol字段值完全匹配,且IntervalStart值为"Pre"的行对应的rate字段值。
最初尝试的实现代码如下:
ipTraceSummary2 %>% mutate( baseline = pull((ipTraceSummary2 %>% filter(`DstPo` == DstPo, `Protocol` == Protocol, `IntervalStart` == "Pre"))[1,"rate"]) )
运行后出现问题:baseline列全部填充为整个数据集中第一个IntervalStart="Pre"行的rate值,没有按照当前行的DstPo、Protocol字段做条件筛选。
错误原因
嵌套在mutate里的filter是直接对全局原始数据集ipTraceSummary2做操作,判断条件DstPo == DstPo、Protocol == Protocol本质是列和自身比较,永远返回真,根本没有引用mutate计算过程中当前行的字段值,所以最终永远返回整个表第一个匹配IntervalStart == "Pre"的行值,所有行结果一致。
可行解法
不要在mutate里嵌套对全表的filter操作,用分组匹配或者表连接的方式实现,性能更好逻辑也更清晰:
- 方法1:左连接匹配(推荐,万行以上数据性能最优)
先单独提取所有DstPo+Protocol组合对应的Pre基准值,再通过左连接把基准值匹配回原表,不需要逐行计算:library(dplyr) # 提取基准值表 baseline_ref <- ipTraceSummary2 %>% filter(IntervalStart == "Pre") %>% select(DstPo, Protocol, baseline = rate) # 连接回原表 result <- ipTraceSummary2 %>% left_join(baseline_ref, by = c("DstPo", "Protocol")) - 方法2:分组内计算(适合管道内连续操作,不需要中间表)
按DstPo、Protocol分组后,直接在组内取Pre对应的rate值即可:result <- ipTraceSummary2 %>% group_by(DstPo, Protocol) %>% mutate(baseline = rate[IntervalStart == "Pre"][1]) %>% ungroup()
提示:如果某个
DstPo+Protocol组合不存在IntervalStart="Pre"的行,对应baseline值会自动填充为NA,符合缺失值逻辑。
内容的提问来源于stack exchange,提问作者Ian
相关产品推荐
相关产品推荐

