《R数据科学》第9章-用dplyr处理关系数据
1. 简介
2. 数据准备:
3. 键
4. 合并连接
5. 筛选连接
6. 连接中的问题
7. 集合操作
1. 简介
通常一张数据表不足以说明问题,需要多个在多个数据表中建立联系,那么怎么做呢?
基本思想:
在两个表之间建立关系。也就是说,每种关系只与两张表有关。
基本操作:
通过三类操作来处理关系数据。
合并连接:向数据框中加入新变量,新变量的值是另一个数据框中的匹配观测。【主要作用于列】
筛选连接:根据是否匹配另一个数据框中的观测,筛选数据框中的观测。【主要作用于行】
集合操作:将观测作为集合元素来处理。
2. 数据准备:
nycflights13 包中的5个tibble
flights:2013年从纽约市出发的所有336776次航班信息。19个变量(year,month,day,dep_time实际出发时间,sched_dep_time预计出发时间,dep_delay出发延误时间,arr_time实际到达时间,sched_arr_time预计到达时间,arr_delay到达延误时间,carrier航空公司,flight航班,tailnum机尾编号,origin起始点,dest目的地,air_time空中停留时间,distance距离,hour预计起飞时间-小时,minute预计起飞时间-分钟,time_hour时间)。
airlines:根据航空公司的缩写码查到公司全名。共16个航空公司,2个变量(carrier缩写,name全称)
airports:每个机场的信息,通过 faa 机场编码进行标识。共1396个机场,7个变量(faa机场编码,name机场名,lat纬度, lon经度,alt高度,tz GMT时差,dst夏令时区,tzone IANA时区)
planes:每架飞机的信息,通过 tailnum 进行标识。共3322个机场,9个变量(tailnum机尾编号,year生产日期,type机型,manufacturer制造商,model,engines引擎数,seats座位数,speed,engine)
weather:纽约机场(起点机场)每小时的天气状况。共26130个小时,15个变量(origin机场所在地,year,month,day,hour,temp温度,dewp露点,humid湿度,wind_dir风向,wind_speed风速,wind_gust,precip降水,pressure气压,visib能见度,time_hour时间)
不同数据表之间的关系:
flights 与 planes 通过单变量 tailnum 相连;
flights 与 airlines 通过变量 carrier 相连;
flights 与 airports 通过两种方式相连(变量 origin 和 dest);
flights 与 weather 通过变量 origin(位置)以及 year、month、day 和 hour(时间)相连。
3. 键
键的定义:
键是能唯一标识观测的变量(或变量集合)。
要点:
能唯一标识观测:在所有观测(行)中,键(一列或几列的集合)对应的值仅出现一次;类似于一个数据表中的行号。
# 验证是否是主键,即是否能唯一标识观测,用代码表示如下
# 方法:对主键进行 count() 操作,然后查看是否有 n 大于 1 的记录
> planes%>%
+ count(tailnum)%>%
+ filter(n>1)
# A tibble: 0 x 2
# ... with 2 variables: tailnum <chr>, n <int>
# 可见,tailnum是planes表的主键# 补充:count()函数
功能:分组计数观测
语法:count(x, ..., wt = NULL, sort = FALSE, name = NULL)
参数说明:
- x 数据框
- ... 要分组的变量
- wt 默认计数每组的行数,默认时不写
- sort 若为TRUE,按计数结果降序排列
- name 输出中新列的名称,默认为n(省略即为默认),如果已有一个名为n的列,会出错。
可以是一个变量(如:每架飞机都可以由 tailnum 唯一标识),也可以是多个变量的集合(如:要想标识 weather 中的观测,需要 5 个变量:year、month、 day、 hour 和 origin)。
键的作用:
用于连接每对数据表。
键的类型:
主键:唯一标识其所在数据表中的观测。例如, planes表中的tailnum 是一个主键,因为其可以唯一标识 planes 表中的每架飞机。
外键:唯一标识另一个数据表中的观测。例如, flights表的中的tailnum 是一个外键,因为其出现在 flights 表中,并可以将每次航班与唯一一架飞机匹配。
一个变量既可以是主键,也可以是外键。例如, origin 是 weather 表主键的一部分,同时 也是 airports 表的外键。
如果一张表没有 主键,需要使用 mutate() 函数和 row_number() 函数为表加上一个主键(如:行号),成为代理键。
# 向 flights 添加一个代理键
flights %>%
arrange(year, month, day, sched_dep_time, carrier, flight) %>%
mutate(flight_id = row_number()) %>%
glimpse()
4. 合并连接
本质:
添加新列(变量),或组合表格
原理:
将一个表格中的变量通过键匹配到另一个表格中
结果:
新表列数=两个表的列数之和-主键列数。新表行数:根据连接方式而定。
4种连接方式:
函数:*_join(x,y,by = NULL)
参数说明:
x,y 两个数据框
by 由要连接的变量(键)组成的字符向量
- 默认:by = NULL,*_join()将执行一个自然连接,使用x和y的所有共同变量。如,匹配flihjts表和weather表时使用的就是其公共变量: year、 month、 day、 hour 和 origin。
flights2 %>%
left_join(weather)
- 两个表中都有某一变量,但意义不同。用字符向量 by = "x"。结果中的同名变量添加一个后缀(.x和.y),以消除歧义。
# flights 和 planes 表中都有 year 变量,但意义不同,因此只通过 tailnum进行连接:
flights2 %>%
left_join(planes, by = "tailnum")
- 同一变量在两个表中的叫法不同。用命名字符向量 by = c("a" = "b"),将匹配 x 表中的 a 变量和 y 表中的 b 变量。输出结果中使用的是 x 表中的变量。
# 每次航班都有起点机场(origin)和终点机场(dest),而airports表中只有机场信息(机场用faa表示,不存在起点或终点的说法),所以需要指定使用哪个机场进行连接
flights2 %>%
left_join(airports, c("dest" = "faa"))
- 要使用多个变量连接,用变量集合by = c("a", "b")将匹配x$a到y$a, x$b到y$b。
内连接inner_join():保留同时存在于两个表中的观测(取交集)。
外连接-左连接left_join():保留 x 中的所有观测。默认是左连接。
外连接-右连接right_join():保留 y 中的所有观测
外连接-全连接full_join():保留 x 和 y 中的所有观测。
说明:
如果没有匹配的键的话,其值用 NA 来填充
当键不唯一时会怎么样?
会得到所有可能的组合。
其他实现方式
base::merge() 函数可以实现所有 4 种合并连接操作。
dplyr 连接操作的优点:①可以更加清晰地表达出代码的意图;②速度明显更快,而且不会弄乱行的顺序。
5. 筛选连接
本质:
筛选行。
类型:
(1) 半连接 semi_join(x, y):
结果:保留 x 表中与 y 表中的观测相匹配的所有观测。(保留x与y中共有的行)
应用:对数据表进行筛选或摘要统计后,如果想要使用表中原来的行来匹配筛选或摘要结果,那么半连接是非常有用的。
# 找出最受欢迎的前 10 个目的地
top_dest <- flights %>%
count(dest, sort = TRUE) %>%
head(10)
top_dest
# 找出飞往这些目的地的所有航班
# 可以自己构造一个筛选器,但这种方法很难扩展到多个变量
flights %>%
filter(dest %in% top_dest$dest)
# 用半连接,可以像合并连接一样连接两个表,但不添加新列,而是保留 x表中那些可以匹配 y 表的行
flights %>%
semi_join(top_dest)
(2)反连接 anti_join(x, y):
结果:丢弃 x 表中与 y 表中的观测相匹配的所有观测(保留仅x中有的行)
应用:用于诊断连接中的不匹配。
# flights 中是否有很多行在 planes 中没有匹配记录:
flights %>%
anti_join(planes, by = "tailnum") %>%
count(tailnum, sort = TRUE)
6. 连接中的问题
为了在使用自己的数据时可以顺畅地进行各种连接,需要注意以下几点。
(1) 首先,需要找出每个表中可以作为主键的变量。一般应该基于对数据的理解来确定主键,在确定主键时需要考虑其实际意义。
(2) 确保主键中的每个变量都没有缺失值。如果有缺失值,那么这个变量就不能标识观测!
(3) 检查外键是否与另一张表的主键相匹配。最好的方法是使用 anti_join()。
7. 集合操作
所有集合操作都是作用于整行 的,比较的是每个变量的值。
作用:可以将一个复杂的筛选操作分解为多个简单部分。
集合操作需要 x 和 y 具有相同的变量,并将观测按照集合来处理。
intersect(x, y):返回既在 x 表,又在 y 表中的观测。
union(x, y):返回 x 表或 y 表中的唯一观测。
setdiff(x, y):返回在 x 表,但不在 y 表中的观测。