使用magrittr管道%>%后调用is.na出现意外结果的原因排查
管道运算符
%>%与运算符优先级的问题解析 问题场景
用==比较两个包含NA元素的字符向量时,希望将==的逻辑输出通过magrittr管道运算符%>%传递给is.na(),但直接编写代码得到意外结果;给==比较整体加括号,或先将==的输出保存为对象后再管道,结果符合预期。
代码示例
# 定义测试对象 cvglists <- structure( list(NULL, NULL, NULL, NULL, NULL), names = c("x", "y", "z", NA, NA) ) bw_use <- list( x = "bigwig_nos", y = "bigwig_nos", z = "bigwig_nos", a = "bigwig_nos", b = "bigwig_nos" ) # 得到意外结果的写法 names(cvglists) == names(bw_use)[1:length(cvglists)] %>% is.na() # [1] FALSE FALSE FALSE NA NA # 符合预期的写法(加括号) (names(cvglists) == names(bw_use)[1:length(cvglists)]) %>% is.na() # [1] FALSE FALSE FALSE TRUE TRUE # 另一种可行写法(临时对象) tmp <- names(cvglists) == names(bw_use)[1:length(cvglists)] tmp %>% is.na() # [1] FALSE FALSE FALSE TRUE TRUE
问题根源:运算符优先级
核心误解在于管道运算符%>%的优先级高于比较运算符==。R中运算符执行有明确的优先级规则,管道运算符的优先级比==更高,导致直接编写的代码执行顺序和预期完全不符:
- 错误写法
names(cvglists) == names(bw_use)[1:length(cvglists)] %>% is.na()的实际执行顺序是:先对names(bw_use)[1:length(cvglists)]执行is.na(),再将这个结果作为==的右侧,和names(cvglists)做比较。 - 而预期逻辑是先执行
names(cvglists) == names(bw_use)[1:length(cvglists)]得到比较结果,再将结果传给is.na()检测其中的NA值。
结合示例具体拆解:
names(bw_use)[1:length(cvglists)]的结果是c("x","y","z","a","b"),执行is.na()后得到全FALSE的向量;- 将这个全
FALSE向量和names(cvglists)(c("x","y","z",NA,NA))做==比较,NA和任何值比较都会返回NA,因此得到FALSE FALSE FALSE NA NA的意外结果; - 加括号后,先执行
==比较得到c(TRUE, TRUE, FALSE, NA, NA),再用is.na()检测其中的NA,得到FALSE FALSE FALSE TRUE TRUE的预期结果。
解决方法
- 给
==比较的整体加上括号,强制改变执行顺序,确保先完成比较再执行管道操作; - 先将
==的比较结果保存为临时对象,再通过管道将该对象传给is.na()。
内容的提问来源于stack exchange,提问作者Josh
相关产品推荐
相关产品推荐

