R语言ETL工程:集合运算(intersect/union/setdiff)

欢迎关注天善智能,我们是专注于商业智能BI,人工智能AI,大数据分析与挖掘领域的垂直社区,学习,问答、求职一站式搞定!

对商业智能BI、大数据分析挖掘、机器学习,python,R等数据领域感兴趣的同学加微信:tstoutiao,邀请你进入数据爱好者交流群,数据爱好者们都在这儿。

R语言ETL工程:集合运算(intersect/union/setdiff)

作者:黄天元,复旦大学博士在读,目前研究涉及文本挖掘、社交网络分析和机器学习等。希望与大家分享学习经验,推广并加深R语言在业界的应用。

邮箱:[email protected]

前文推送:

R语言ETL系列:汇总(summarise)

R语言ETL工程:分组(group_by)

R语言ETL工程:连接(join)


集合运算与连接其实有相似之处,但是连接是针对特定列(主键)来对表格进行连接,而集合运算则直接对记录(entry)进行运算。简单来说,就是以行为单位进行运算。假设表格A与表格B有相同的列名称,它们其实数据的来源是相同的,但是记录的东西有重复的部分,又有不一样的地方。如果我们想要知道哪些部分重复了,就需要求两个数据的交集。简单来讲,本章就是要讲数据记录的“交、并、补”运算。具体的运算逻辑如下图所示:


R语言ETL工程:集合运算(intersect/union/setdiff)

集合运算基本逻辑

内容比较简单,我们直接上例子。本章用到的数据集主要是mtcars,我们把它转化为tibble然后进行演示。环境准备如下:

 1library(tidyverse)
2mtcars %>% 
3rownames_to_column(var = "type") %>% #把行名称转为其中一列
4as_tibble() -> mtcars1 #转化为tibble格式
5
6mtcars1
7
8## # A tibble: 32 x 12
9## type mpg cyl disp hp drat wt qsec vs am gear carb
10## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
11## 1 Mazda~ 21 6 160 110 3.9 2.62 16.5 0 1 4 4
12## 2 Mazda~ 21 6 160 110 3.9 2.88 17.0 0 1 4 4
13## 3 Datsu~ 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
14## 4 Horne~ 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1
15## 5 Horne~ 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2
16## 6 Valia~ 18.1 6 225 105 2.76 3.46 20.2 1 0 3 1
17## 7 Duste~ 14.3 8 360 245 3.21 3.57 15.8 0 0 3 4
18## 8 Merc ~ 24.4 4 147. 62 3.69 3.19 20 1 0 4 2
19## 9 Merc ~ 22.8 4 141. 95 3.92 3.15 22.9 1 0 4 2
20## 10 Merc ~ 19.2 6 168. 123 3.92 3.44 18.3 1 0 4 4
21## # ... with 22 more rows


这样还不能够满足我们距离的需要,现在我们对这个数据集取两个子集,一个是从第1到第6列,第二个是从第3到第8列,分别存在变量a和变量b中。


 1mtcars1 %>%
2slice(1:6) -> a
3
4mtcars1 %>%
5slice(3:8) -> b
6
7a
8
9## # A tibble: 6 x 12
10## type mpg cyl disp hp drat wt qsec vs am gear carb
11## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
12## 1 Mazda ~ 21 6 160 110 3.9 2.62 16.5 0 1 4 4
13## 2 Mazda ~ 21 6 160 110 3.9 2.88 17.0 0 1 4 4
14## 3 Datsun~ 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
15## 4 Hornet~ 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1
16## 5 Hornet~ 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2
17## 6 Valiant 18.1 6 225 105 2.76 3.46 20.2 1 0 3 1
18
19b
20
21## # A tibble: 6 x 12
22## type mpg cyl disp hp drat wt qsec vs am gear carb
23## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
24## 1 Datsun~ 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
25## 2 Hornet~ 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1
26## 3 Hornet~ 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2
27## 4 Valiant 18.1 6 225 105 2.76 3.46 20.2 1 0 3 1
28## 5 Duster~ 14.3 8 360 245 3.21 3.57 15.8 0 0 3 4
29## 6 Merc 2~ 24.4 4 147. 62 3.69 3.19 20 1 0 4 2


仔细看两分数据,我们知道他们有重叠的部分,也有不同的部分。下面我们来分别举例。


交(interset)

 1a %>%
2intersect(b)
3
4## # A tibble: 4 x 12
5## type mpg cyl disp hp drat wt qsec vs am gear carb
6## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
7## 1 Datsun~ 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
8## 2 Hornet~ 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1
9## 3 Hornet~ 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2
10## 4 Valiant 18.1 6 225 105 2.76 3.46 20.2 1 0 3 1


我们发现两个表中,有四行是一样的。

SQL代码为:


1<SQL> SELECT *
2FROM `a`
3INTERSECT
4SELECT *
5FROM `b`


并(union)

 1a %>%
2dplyr::union(b)
3
4## # A tibble: 8 x 12
5## type mpg cyl disp hp drat wt qsec vs am gear carb
6## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
7## 1 Merc 2~ 24.4 4 147. 62 3.69 3.19 20 1 0 4 2
8## 2 Duster~ 14.3 8 360 245 3.21 3.57 15.8 0 0 3 4
9## 3 Mazda ~ 21 6 160 110 3.9 2.88 17.0 0 1 4 4
10## 4 Hornet~ 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1
11## 5 Datsun~ 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
12## 6 Mazda ~ 21 6 160 110 3.9 2.62 16.5 0 1 4 4
13## 7 Valiant 18.1 6 225 105 2.76 3.46 20.2 1 0 3 1
14## 8 Hornet~ 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2


注意在这个步骤中,我们使用了“dplyr::”放在函数union之前,为什么呢?因为很多包(包括基本包)都会有同名函数union尽管有时候加载的时候会互相覆盖掉,这样就会发生歧义。因此如果我们知道一些函数的命名太过常见,就应该在函数之前加上包的名字和两个冒号,来声明我们用的是这个包里面的这个函数。


SQL代码为:


1<SQL> SELECT *
2FROM `a`
3UNION
4SELECT *
5FROM `b`


在我们进行“并”运算的时候,两个表格重复的部分在新表格中只会出现一次。如果我们想要的是记录的单纯叠加的话,可以这么做:


 1a %>%
2union_all(b)
3
4## # A tibble: 12 x 12
5## type mpg cyl disp hp drat wt qsec vs am gear carb
6## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
7## 1 Mazda~ 21 6 160 110 3.9 2.62 16.5 0 1 4 4
8## 2 Mazda~ 21 6 160 110 3.9 2.88 17.0 0 1 4 4
9## 3 Datsu~ 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
10## 4 Horne~ 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1
11## 5 Horne~ 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2
12## 6 Valia~ 18.1 6 225 105 2.76 3.46 20.2 1 0 3 1
13## 7 Datsu~ 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
14## 8 Horne~ 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1
15## 9 Horne~ 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2
16## 10 Valia~ 18.1 6 225 105 2.76 3.46 20.2 1 0 3 1
17## 11 Duste~ 14.3 8 360 245 3.21 3.57 15.8 0 0 3 4
18## 12 Merc ~ 24.4 4 147. 62 3.69 3.19 20 1 0 4 2


SQL代码:


1<SQL> SELECT *
2FROM `a`
3UNION ALL
4SELECT *
5FROM `b`


补(setdiff)

1a %>% 
2setdiff(b)
3
4## # A tibble: 2 x 12
5## type mpg cyl disp hp drat wt qsec vs am gear carb
6## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
7## 1 Mazda ~ 21 6 160 110 3.9 2.62 16.5 0 1 4 4
8## 2 Mazda ~ 21 6 160 110 3.9 2.88 17.0 0 1 4 4


这样我们得到的是表格a中有,而表格b中没有的记录。 SQL代码:


1<SQL> SELECT *
2FROM `a`
3EXCEPT
4SELECT *
5FROM `b`


判断是否相等(setequal)

dplyr中的函数还可以支持判断两个集合是否相等,这里判断标准是记录是否都一样,返回一个逻辑值(T/F)。判断表格是否相等,只跟内容有关,跟内容的排列顺序无关。

1a %>%
2setequal(b)
3
4## [1] FALSE
5
6mtcars1 %>%
7setequal(mtcars1[32:1,]) #mtcars1[32:1,]中,我们把mtcars1所有记录倒序排列了
8
9## [1] TRUE


小结

本章讲述了集合运算,即集合之间的交、并、补运算,当我们把表格记录视为对象的时候,这些操作能够帮助我们找到两个表格中重复的记录、不同的记录,还可以判断两个表格是否相同。


——————————————

往期精彩:

被知乎反杀,是一种什么体验?


字节跳动“车轮”收割


清华、北大、浙大的计算机课程资源集都在这里了


R语言中文社区2018年终文章整理(作者篇)

R语言中文社区2018年终文章整理(类型篇)

R语言ETL工程:集合运算(intersect/union/setdiff)