有时候我们要分析的数据可能不是来自一个数据集,此时需要我们对不同表按照某一关键字进行连接 假设我们想探索美国各州的人口规模与选举人票之间的关系。我们的人口规模如下表所示:
library(tidyverse)
library(dslabs)
head(murders)
state | abb | region | population | total | |
---|---|---|---|---|---|
<chr> | <chr> | <fct> | <dbl> | <dbl> | |
1 | Alabama | AL | South | 4779736 | 135 |
2 | Alaska | AK | West | 710231 | 19 |
3 | Arizona | AZ | West | 6392017 | 232 |
4 | Arkansas | AR | South | 2915918 | 93 |
5 | California | CA | West | 37253956 | 1257 |
6 | Colorado | CO | West | 5029196 | 65 |
选票数据如下
head(results_us_election_2016)
state | electoral_votes | clinton | trump | others | |
---|---|---|---|---|---|
<chr> | <int> | <dbl> | <dbl> | <dbl> | |
1 | California | 55 | 61.7 | 31.6 | 6.7 |
2 | Texas | 38 | 43.2 | 52.2 | 4.5 |
3 | Florida | 29 | 47.8 | 49.0 | 3.2 |
4 | New York | 29 | 59.0 | 36.5 | 4.5 |
5 | Illinois | 20 | 55.8 | 38.8 | 5.4 |
6 | Pennsylvania | 20 | 47.9 | 48.6 | 3.6 |
直接将这两个表拼接在一起是不对的,因为他们的顺序不一致,因此我们需要考虑按照state连接两个表
left()函数是根据某个关键字列来将多个表进行合并。和sql中的语法基本类似,大家如果想了解sql语法可以看我的专栏。 一般的做法是,首先确定一个或多个用于匹配两个表的列,然后返回一个包含组合数据的新表。
下面,我们使用left_join连接两个表,并且去除others
的列,并将electoral_votes
重命名
tab <- right_join(murders, results_us_election_2016, by = "state") %>%
select(-others) %>% rename(ev=electoral_votes)
head(tab)
state | abb | region | population | total | ev | clinton | trump | |
---|---|---|---|---|---|---|---|---|
<chr> | <chr> | <fct> | <dbl> | <dbl> | <int> | <dbl> | <dbl> | |
1 | Alabama | AL | South | 4779736 | 135 | 9 | 34.4 | 62.1 |
2 | Alaska | AK | West | 710231 | 19 | 3 | 36.6 | 51.3 |
3 | Arizona | AZ | West | 6392017 | 232 | 11 | 45.1 | 48.7 |
4 | Arkansas | AR | South | 2915918 | 93 | 6 | 33.7 | 60.6 |
5 | California | CA | West | 37253956 | 1257 | 55 | 61.7 | 31.6 |
6 | Colorado | CO | West | 5029196 | 65 | 9 | 48.2 | 43.3 |
现在我们成功的将两个表连接在一起了,下面我们简单绘制一下人口和选票之间的关系
tab %>% ggplot(aes(population/10^6, ev, label = abb)) +
geom_point() +
geom_text_repel() +
scale_x_continuous(trans = "log2") +
scale_y_continuous(trans = "log2") +
geom_smooth(method = "lm", se = FALSE)
`geom_smooth()` using formula 'y ~ x'
Warning message:
"ggrepel: 15 unlabeled data points (too many overlaps). Consider increasing max.overlaps"
从结果来看,可以看出人口越多,选票越多,平均而言每十万人有2选票,但是在人口较少的州,这个比例稍高
实际上,并不总是一个表中的每一行在另一个表中都有一个匹配的行。因此,我们有不同的连接方法,为例举例说明, 下面我们先创建tab1和tab2
tab_1 <- slice(murders, 1:6) %>% select(state, population)
tab_1
state | population |
---|---|
<chr> | <dbl> |
Alabama | 4779736 |
Alaska | 710231 |
Arizona | 6392017 |
Arkansas | 2915918 |
California | 37253956 |
Colorado | 5029196 |
tab_2 <- results_us_election_2016 %>%
filter(state%in%c("Alabama", "Alaska", "Arizona",
"California", "Connecticut", "Delaware")) %>%
select(state, electoral_votes) %>% rename(ev = electoral_votes)
tab_2
state | ev |
---|---|
<chr> | <int> |
California | 55 |
Arizona | 11 |
Alabama | 9 |
Connecticut | 7 |
Alaska | 3 |
Delaware | 3 |
假设我们想要一张像tab_1这样的表格,但将选举人票添加到我们现有州。此时tab_1作为第一个参数。我们指定要使用哪个列与by参数匹配。没能匹配到的会自动返回NA
left_join(tab_1,tab_2,by = 'state')
state | population | ev |
---|---|---|
<chr> | <dbl> | <int> |
Alabama | 4779736 | 9 |
Alaska | 710231 | 3 |
Arizona | 6392017 | 11 |
Arkansas | 2915918 | NA |
California | 37253956 | 55 |
Colorado | 5029196 | NA |
可以看出Arkansas
和Colorado
的ev没有匹配到,所以返回NA,下面我们将tab_2传入第一个参数
left_join(tab_2,tab_1,by = 'state')
state | ev | population |
---|---|---|
<chr> | <int> | <dbl> |
California | 55 | 37253956 |
Arizona | 11 | 6392017 |
Alabama | 9 | 4779736 |
Connecticut | 7 | NA |
Alaska | 3 | 710231 |
Delaware | 3 | NA |
可以看出结果返回了包含了tab_2的所有信息,其中Connecticut和Delaware的population返回NV
右连接与左连接相反,返回第二个表的全部信息,匹配连接第一个表,下面我们来看一个案例
tab_2 %>% right_join(tab_1, by = "state")
state | ev | population |
---|---|---|
<chr> | <int> | <dbl> |
California | 55 | 37253956 |
Arizona | 11 | 6392017 |
Alabama | 9 | 4779736 |
Alaska | 3 | 710231 |
Arkansas | NA | 2915918 |
Colorado | NA | 5029196 |
可以看出结果交换参数位置后使用右连接和直接使用左连接的结果一致。
可以这样理解:
如果我们只希望得到两个表中都包含的信息,我们可以使用内连接,没有匹配到的行将不显示
inner_join(tab_1, tab_2, by = "state")
state | population | ev |
---|---|---|
<chr> | <dbl> | <int> |
Alabama | 4779736 | 9 |
Alaska | 710231 | 3 |
Arizona | 6392017 | 11 |
California | 37253956 | 55 |
如果我们希望保留两个表的所有行,并且用NA来填充未匹配到的值,如下所示
full_join(tab_1, tab_2, by = "state")
state | population | ev |
---|---|---|
<chr> | <dbl> | <int> |
Alabama | 4779736 | 9 |
Alaska | 710231 | 3 |
Arizona | 6392017 | 11 |
Arkansas | 2915918 | NA |
California | 37253956 | 55 |
Colorado | 5029196 | NA |
Connecticut | NA | 7 |
Delaware | NA | 3 |
这个方法在mysql中没有涉及到,它具体工作原理是匹配两个表都有的行,然后只显示第一个表的信息。 相当于先做内连接,再把第二个表的信息去除,具体如下:
semi_join(tab_1, tab_2, by = "state")
state | population |
---|---|
<chr> | <dbl> |
Alabama | 4779736 |
Alaska | 710231 |
Arizona | 6392017 |
California | 37253956 |
函数anti_join与semi_join相反。它保留第一个表中没有匹配到第二个表中信息的元素,具体如下
anti_join(tab_1, tab_2, by = "state")
state | population |
---|---|
<chr> | <dbl> |
Arkansas | 2915918 |
Colorado | 5029196 |
另一个连接表的方法是使用binding,和join函数不同,binding函数不通过某个变量匹配,而是直接连接数据框,如果两个数据框纬度不同,则会报错
使用bind_cols,可以方便的连接不同列,例如
bind_cols (a=1:3,b=4:6)
a | b |
---|---|
<int> | <int> |
1 | 4 |
2 | 5 |
3 | 6 |
注意,有一个R函数cbind具有完全相同的功能。 主要区别是cbind可以创建不同类型的对象,而bind_cols总是生成一个数据框。
bind_cols也可以连接不同的数据框,如下所示
tab_1 <- tab[, 1:3]
tab_2 <- tab[, 4:6]
tab_3 <- tab[, 7:8]
new_tab <- bind_cols(tab_1, tab_2, tab_3)
head(new_tab)
state | abb | region | population | total | ev | clinton | trump | |
---|---|---|---|---|---|---|---|---|
<chr> | <chr> | <fct> | <dbl> | <dbl> | <int> | <dbl> | <dbl> | |
1 | Alabama | AL | South | 4779736 | 135 | 9 | 34.4 | 62.1 |
2 | Alaska | AK | West | 710231 | 19 | 3 | 36.6 | 51.3 |
3 | Arizona | AZ | West | 6392017 | 232 | 11 | 45.1 | 48.7 |
4 | Arkansas | AR | South | 2915918 | 93 | 6 | 33.7 | 60.6 |
5 | California | CA | West | 37253956 | 1257 | 55 | 61.7 | 31.6 |
6 | Colorado | CO | West | 5029196 | 65 | 9 | 48.2 | 43.3 |
bind_rows()和bind_cols()函数类似,但是是按行连接
tab_1 <- tab[1:2,]
tab_2 <- tab[3:4,]
bind_rows(tab_1, tab_2)
state | abb | region | population | total | ev | clinton | trump |
---|---|---|---|---|---|---|---|
<chr> | <chr> | <fct> | <dbl> | <dbl> | <int> | <dbl> | <dbl> |
Alabama | AL | South | 4779736 | 135 | 9 | 34.4 | 62.1 |
Alaska | AK | West | 710231 | 19 | 3 | 36.6 | 51.3 |
Arizona | AZ | West | 6392017 | 232 | 11 | 45.1 | 48.7 |
Arkansas | AR | South | 2915918 | 93 | 6 | 33.7 | 60.6 |
同样的,R语言基础函数rbin()可以实现类似的功能
另一组用于连接数据集方法是集合运算符。当运用在向量上面,则实现和它们字面意思一样,例如intersect、union、setdiff和setequal。 则这些函数可以用于数据帧,而不仅仅是向量。
intersect(1:10, 6:15)
.list-inline {list-style: none; margin:0; padding: 0} .list-inline>li {display: inline-block} .list-inline>li:not(:last-child)::after {content: "\00b7"; padding: 0 .5ex}
intersect(c("a","b","c"), c("b","c","d"))
.list-inline {list-style: none; margin:0; padding: 0} .list-inline>li {display: inline-block} .list-inline>li:not(:last-child)::after {content: "\00b7"; padding: 0 .5ex}
当我们导入了dyply包,我们可以使用intersect应用在数据框上,其功能也是求交集
tab_1 <- tab[1:5,]
tab_2 <- tab[3:7,]
intersect(tab_1, tab_2)
state | abb | region | population | total | ev | clinton | trump |
---|---|---|---|---|---|---|---|
<chr> | <chr> | <fct> | <dbl> | <dbl> | <int> | <dbl> | <dbl> |
Arizona | AZ | West | 6392017 | 232 | 11 | 45.1 | 48.7 |
Arkansas | AR | South | 2915918 | 93 | 6 | 33.7 | 60.6 |
California | CA | West | 37253956 | 1257 | 55 | 61.7 | 31.6 |
union(1:10, 6:15)
.list-inline {list-style: none; margin:0; padding: 0} .list-inline>li {display: inline-block} .list-inline>li:not(:last-child)::after {content: "\00b7"; padding: 0 .5ex}
union(c("a","b","c"), c("b","c","d"))
.list-inline {list-style: none; margin:0; padding: 0} .list-inline>li {display: inline-block} .list-inline>li:not(:last-child)::after {content: "\00b7"; padding: 0 .5ex}
tab_1 <- tab[1:5,]
tab_2 <- tab[3:7,]
dplyr::union(tab_1, tab_2)
state | abb | region | population | total | ev | clinton | trump |
---|---|---|---|---|---|---|---|
<chr> | <chr> | <fct> | <dbl> | <dbl> | <int> | <dbl> | <dbl> |
Alabama | AL | South | 4779736 | 135 | 9 | 34.4 | 62.1 |
Alaska | AK | West | 710231 | 19 | 3 | 36.6 | 51.3 |
Arizona | AZ | West | 6392017 | 232 | 11 | 45.1 | 48.7 |
Arkansas | AR | South | 2915918 | 93 | 6 | 33.7 | 60.6 |
California | CA | West | 37253956 | 1257 | 55 | 61.7 | 31.6 |
Colorado | CO | West | 5029196 | 65 | 9 | 48.2 | 43.3 |
Connecticut | CT | Northeast | 3574097 | 97 | 7 | 54.6 | 40.9 |
返回第一个参数对第二个参数的差集,因此和上面两个方法不同,setdiff不是对称的,具体案例如下
setdiff(1:10, 6:15)
setdiff(6:15, 1:10)
.list-inline {list-style: none; margin:0; padding: 0} .list-inline>li {display: inline-block} .list-inline>li:not(:last-child)::after {content: "\00b7"; padding: 0 .5ex}
.list-inline {list-style: none; margin:0; padding: 0} .list-inline>li {display: inline-block} .list-inline>li:not(:last-child)::after {content: "\00b7"; padding: 0 .5ex}
tab_1 <- tab[1:5,]
tab_2 <- tab[3:7,]
dplyr::setdiff(tab_1, tab_2)
state | abb | region | population | total | ev | clinton | trump |
---|---|---|---|---|---|---|---|
<chr> | <chr> | <fct> | <dbl> | <dbl> | <int> | <dbl> | <dbl> |
Alabama | AL | South | 4779736 | 135 | 9 | 34.4 | 62.1 |
Alaska | AK | West | 710231 | 19 | 3 | 36.6 | 51.3 |
setequal
判断两个集合是否相等,而不管顺序。例如
setequal(1:5, 1:6)
FALSE
setequal(1:5, 5:1)
TRUE
setequal(tab_1, tab_2)
FALSE
阅读量:1978
点赞量:0
收藏量:0