如何在单个dplyr管道中通过两次自连接筛选数据框?
问题:筛选FirstComponent和SecondComponent均存在于Structure列的行
给定如下R语言tibble数据框dat,需要构建单个dplyr管道,仅保留FirstComponent和SecondComponent的值均存在于Structure列中的行(即IsValid为TRUE的行)。
数据框定义
library(dplyr) dat <- tibble( Structure = c("A", "B", "X", "A-X", "B-X", "C-X", "A-Y"), FirstComponent = c(NA, NA, NA, "A", "B", "C", "A"), SecondComponent = c(NA, NA, NA, "X", "X", "X", "Y"), IsValid = c(FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE))
失败的尝试方案
方案1:嵌套inner_join报错
dat %>% inner_join( x=inner_join( x=., y=select(., FirstComponent=Structure)), y=select(., SecondComponent=Structure))
报错信息:Can't subset columns that don't exist. ✖ Columns xandy don't exist.
原因:inner_join无需显式指定x=和y=参数,嵌套写法导致占位符.的作用域混乱,无法识别正确列。
方案2:连续两次自连接结果为空
dat %>% inner_join( x=., y=select(., FirstComponent=Structure)) %>% inner_join( x=., y=select(., SecondComponent=Structure))
结果:空数据框
原因:第一次inner_join后已过滤部分行,第二次连接时的.指向过滤后的数据集而非原始数据,导致无法匹配到正确的结构值。
可行的解决方法
方法1:使用semi_join两次(推荐)
semi_join仅保留匹配行且不重复添加列,每次基于原始数据验证存在性:
dat %>% semi_join(dat, by = c("FirstComponent" = "Structure")) %>% semi_join(dat, by = c("SecondComponent" = "Structure"))
方法2:使用filter结合%in%
直接通过逻辑判断筛选,写法更直观:
dat %>% filter( FirstComponent %in% Structure, SecondComponent %in% Structure )
方法3:修正inner_join写法
若坚持使用inner_join,需确保每次连接引用原始dat而非管道中的当前数据:
dat %>% inner_join(select(dat, Structure), by = c("FirstComponent" = "Structure")) %>% inner_join(select(dat, Structure), by = c("SecondComponent" = "Structure"))
以上三种方法均可得到正确结果,保留IsValid为TRUE的两行数据。
内容的提问来源于stack exchange,提问作者Schmuddi
相关产品推荐
相关产品推荐

