确认dplyr::filter()两种写法的输出与执行逻辑是否一致
关于dplyr::filter()两种写法的疑问
我目前正在通过Grolemund与Wickham所著的《R for Data Science》(R4DS)学习tidyverse包。在实操代码时,发现使用dplyr的filter()函数时,两种写法得到了相同输出,希望确认以下三点:
- (a) 两种写法的输出是否完全一致;
- (b) 输出是否存在未察觉的差异;
- (c) 输出相同但执行逻辑是否不同。
前置代码
首先加载所需包:
library(nycflights13) library(tidyverse)
写法1
flights %>% filter(arr_delay >= 120) %>% filter(dest == "IAH" | dest == "HOU") %>% filter(carrier == "UA" | carrier == "AA" | carrier == "DL") %>% filter(month >= 7 & month <= 9)
写法2
flights %>% filter(arr_delay >= 120, dest == "IAH" | dest == "HOU", carrier == "UA" | carrier == "AA" | carrier == "DL", month >= 7 & month <= 9)
两种写法的共同输出
两种写法均得到如下相同的tibble输出:
# A tibble: 47 x 19 year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier <int> <int> <int> <int> <int> <dbl> <int> <int> <dbl> <chr> 1 2013 7 1 1310 1057 133 1551 1338 133 UA 2 2013 7 1 1707 1448 139 1943 1742 121 UA 3 2013 7 1 2058 1735 203 2355 2030 205 AA 4 2013 7 2 2001 1735 146 2335 2030 185 AA 5 2013 7 3 2215 1909 186 45 2200 165 UA 6 2013 7 9 1937 1735 122 2240 2030 130 AA 7 2013 7 10 40 1909 331 301 2200 301 UA 8 2013 7 10 1629 1520 69 2048 1754 174 UA 9 2013 7 10 1913 1721 112 2214 2001 133 UA 10 2013 7 17 1657 1446 131 2007 1745 142 UA # ... with 37 more rows, and 9 more variables: flight <int>, tailnum <chr>, origin <chr>, # dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
解答
(a) 输出完全一致
两种写法的输出完全相同。因为filter()函数的多个参数默认是逻辑与(&)关系,写法1中多次链式调用filter(),本质是逐步叠加逻辑与条件,和写法2中把所有条件放在同一个filter()里用逗号分隔的效果完全等价。
(b) 不存在未察觉的差异
只要数据中没有NA值干扰(或已处理NA),两种写法的输出不会有任何隐藏差异。即使存在NA,filter()对NA的处理逻辑也一致:会自动移除条件结果为NA的行,无论分多次调用还是单次调用,最终过滤规则完全相同。
(c) 执行逻辑有细微差别,但结果等价
- 写法1是分步过滤:每次调用
filter()都会生成一个中间数据集,再传递给下一个filter()。比如先筛选arr_delay >=120的行,再在这个子集里筛选dest符合条件的行,以此类推。 - 写法2是单次过滤:把所有条件合并成一个大的逻辑表达式(所有条件用
&连接),一次性完成筛选,不会生成中间数据集。
不过在dplyr的优化机制下,针对内存中的常规数据集,两种写法的性能差异几乎可以忽略。只有处理超大规模数据集或数据库后端(如dbplyr连接数据库)时,单次过滤可能生成更高效的查询语句,但最终结果始终一致。
内容的提问来源于stack exchange,提问作者Rohan Sarkar
相关产品推荐
相关产品推荐

