5. 过滤连接
过滤连接与可变连接匹配观察值的方式相同,但是会影响观察值,而不影响变量。
分为两种类型:
-
semi_join(x, y)
:保留x
中所有与y
匹配的观察值 -
anti_join(x, y)
:删除x
中所有与y
匹配的观察值
semi_join
对于将筛选后的汇总表与原始数据进行匹配非常有用。
例如,您想要找到了人流量最多的十大目的地:
> top_dest <- flights %>%
+ count(dest, sort = TRUE) %>%
+ head(10)
> top_dest
# A tibble: 10 x 2
dest n
<chr> <int>
1 ORD 17283
2 ATL 17215
3 LAX 16174
4 BOS 15508
5 MCO 14082
6 CLT 14064
7 SFO 13331
8 FLL 12055
9 MIA 11728
10 DCA 9705
现在,您想要查找去往那些目的地之一的航班
> flights %>%
+ filter(dest %in% top_dest$dest) %>%
+ head(5)
# A tibble: 5 x 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier flight
<int> <int> <int> <int> <int> <dbl> <int> <int> <dbl> <chr> <int>
1 2013 1 1 542 540 2 923 850 33 AA 1141
2 2013 1 1 554 600 -6 812 837 -25 DL 461
3 2013 1 1 554 558 -4 740 728 12 UA 1696
4 2013 1 1 555 600 -5 913 854 19 B6 507
5 2013 1 1 557 600 -3 838 846 -8 B6 79
# … with 8 more variables: tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
但是很难将该方法扩展到多个变量。
例如,假设您知道平均延迟时间最高的十天,您将如何使用 year
, month
和 day
来构造一个能够匹配 flights
中所有航班的过滤器?
而 semi-join
的连接方式与可变连接类似,但是不会添加新的列,而是保留 x
中所有与 y
匹配的观察值。
> flights %>%
+ semi_join(top_dest) %>%
+ head(5)
Joining, by = "dest"
# A tibble: 5 x 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier flight
<int> <int> <int> <int> <int> <dbl> <int> <int> <dbl> <chr> <int>
1 2013 1 1 542 540 2 923 850 33 AA 1141
2 2013 1 1 554 600 -6 812 837 -25 DL 461
3 2013 1 1 554 558 -4 740 728 12 UA 1696
4 2013 1 1 555 600 -5 913 854 19 B6 507
5 2013 1 1 557 600 -3 838 846 -8 B6 79
# … with 8 more variables: tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
从图像上看是这样的
![](http://upload-images.jianshu.io/upload_images/18546936-427a12d37e623ad2.png)
只有匹配的行才会保留下来,而且不会像可变连接一样重复行
![](http://upload-images.jianshu.io/upload_images/18546936-13fbd0cdde262fd3.png)
semi-join
的逆是 anti-join
,anti-join
保留不匹配的行
![](http://upload-images.jianshu.io/upload_images/18546936-fa2232e16f5f4705.png)
anti-join
对于不匹配的观察值很有用。例如,你想知道 flights
与 planes
有多少不匹配的
> flights %>%
+ anti_join(planes, by = "tailnum") %>%
+ count(tailnum, sort = TRUE) %>% head(5)
# A tibble: 5 x 2
tailnum n
<chr> <int>
1 NA 2512
2 N725MQ 575
3 N722MQ 513
4 N723MQ 507
5 N713MQ 483
5.1 思考练习
航班缺少
tailnum
是什么意思?在planes
上没有匹配记录的tailnum
有什么共同点? (提示:有一个变量可解释大约90%
的问题)找到延迟
48
小时的航班,与weather
表连接后能看出什么信息?试着解释下面两行命令
anti_join(flights, airports, by = c("dest" = "faa"))
anti_join(airports, flights, by = c("faa" = "dest"))
6. 连接的问题
我们所使用的数据是已经被清洗过的,尽可能的为你减少不必要的麻烦。
但是你自己的数据可能不是很好,因此需要先对自己的数据做一些事情,以使连接能够顺利进行。
- 首先,要确定每个表中的主键。通常,应该基于对数据的理解来执行此操作,而不是凭经验来寻找唯一标识符的变量组合
例如,纬度和经度可以唯一地标识每个机场,但是它们并不是很好的标识符
> airports %>% count(alt, lon) %>% filter(n > 1)
# A tibble: 0 x 3
# … with 3 variables: alt <dbl>, lon <dbl>, n <int>
确保主键中没有任何变量确实。如果存在缺失值,则可能无法识别观察值
检查您的外键是否与另一个表中的主键匹配。最好的方法是使用
anti_join()
。
7. 集合操作
集合操作包括三个:
-
intersect(x, y)
: 返回x
和y
的交集 -
union(x, y)
: 返回x
和y
的并集 -
setdiff(x, y)
: 返回x
和y
的差集
对于数据集
df1 <- tribble(
~x, ~y,
1, 1,
2, 1
)
df2 <- tribble(
~x, ~y,
1, 1,
1, 2
)
有 4 种操作
> intersect(df1, df2)
# A tibble: 1 x 2
x y
<dbl> <dbl>
1 1 1
> union(df1, df2)
# A tibble: 3 x 2
x y
<dbl> <dbl>
1 1 1
2 2 1
3 1 2
> setdiff(df1, df2)
# A tibble: 1 x 2
x y
<dbl> <dbl>
1 2 1
> setdiff(df2, df1)
# A tibble: 1 x 2
x y
<dbl> <dbl>
1 1 2
8. 补充
dplyr
的大部分内容我们已经讲完了,剩下的一部分函数大家可以查看下面的速查表获取使用方法
![](http://upload-images.jianshu.io/upload_images/18546936-142dd0625af53ffe.png)
![](http://upload-images.jianshu.io/upload_images/18546936-aae566452ce8daea.png)
也可以在公众号 生信学习手册 后台回复 dplyr
获取该包的速查表 PDF
版。