R语言ETL工程:分组(group_by)
欢迎关注天善智能,我们是专注于商业智能BI,人工智能AI,大数据分析与挖掘领域的垂直社区,学习,问答、求职一站式搞定!
对商业智能BI、大数据分析挖掘、机器学习,python,R等数据领域感兴趣的同学加微信:tstoutiao,邀请你进入数据爱好者交流群,数据爱好者们都在这儿。
作者:黄天元,复旦大学博士在读,目前研究涉及文本挖掘、社交网络分析和机器学习等。希望与大家分享学习经验,推广并加深R语言在业界的应用。
邮箱:huang.tian-yuan@qq.com
本章会讲解如何对数据进行分组。首先我们要明确一点,就是为什么要分组,实际应用的场景是什么?
如果我们现在有一个学校,我们想要分别得到男生和女生的平均身高,就需要分组,也就是根据性别对学生的身高分组,然后分别求平均值。这个例子我们只是分了两组,可能大家还看不到分组的力量。那么,如果我们现在要知道每一个班级数学成绩的平均分,那么我们就要对数据成绩根据班级分组,比如我们一个年级有12个班级,那么就要对12个班级分别计算平均分。当分组的数量越多的时候,如果没有分组的操作,分开来一个一个计算是极其耗时的。所以分组功能在实际工作中,具有非常广泛的应用。
下面我们围绕分组进行举例分析,这次我们会用到R语言自带的mtcars数据集,首先我们把它转化成tibble形式,然后存放在mtcars1中。准备代码如下:
1library(tidyverse)
2
3mtcars %>% as_tibble() -> mtcars1
4
5mtcars1
6
7## # A tibble: 32 x 11
8## mpg cyl disp hp drat wt qsec vs am gear carb
9## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
10## 1 21 6 160 110 3.9 2.62 16.5 0 1 4 4
11## 2 21 6 160 110 3.9 2.88 17.0 0 1 4 4
12## 3 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
13## 4 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1
14## 5 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2
15## 6 18.1 6 225 105 2.76 3.46 20.2 1 0 3 1
16## 7 14.3 8 360 245 3.21 3.57 15.8 0 0 3 4
17## 8 24.4 4 147. 62 3.69 3.19 20 1 0 4 2
18## 9 22.8 4 141. 95 3.92 3.15 22.9 1 0 4 2
19## 10 19.2 6 168. 123 3.92 3.44 18.3 1 0 4 4
20## # ... with 22 more rows
分组操作
要在R语言中做分组操作,只需要使用group_by函数即可,在函数中放入想要根据什么分组,也就是分组的列名称。 下面,我们会根据汽车的气缸数量(cyl)分组,然后取各自前三个记录进行展示:
1mtcars1 %>%
2group_by(cyl) %>% #根据cyl进行分组
3slice(1:3) #取每个分组的1~3个记录
4
5## # A tibble: 9 x 11
6## # Groups: cyl [3]
7## mpg cyl disp hp drat wt qsec vs am gear carb
8## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
9## 1 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
10## 2 24.4 4 147. 62 3.69 3.19 20 1 0 4 2
11## 3 22.8 4 141. 95 3.92 3.15 22.9 1 0 4 2
12## 4 21 6 160 110 3.9 2.62 16.5 0 1 4 4
13## 5 21 6 160 110 3.9 2.88 17.0 0 1 4 4
14## 6 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1
15## 7 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2
16## 8 14.3 8 360 245 3.21 3.57 15.8 0 0 3 4
17## 9 16.4 8 276. 180 3.07 4.07 17.4 0 0 3 3
通过结果我们可以看到,我们把4个气缸、6个气缸和8个气缸的汽车都提取了前面3条记录。
取消分组
需要注意的是,如果我们进行group_by操作之后,整个数据表就处于一种分组的状态,也就是说,所有的操作都是基于分组进行,也就是会分别对组内的数据操作。如果你有n个分组,那么我们会得到n份结果。有的时候我们进行分组运算以后,就需要对数据进行重新分组,或者就可以直接取消分组做其他操作了,那么应该怎么办?这时候应该使用ungroup函数。
1mtcars1 %>%
2group_by(cyl) %>%
3slice(1:3) %>%
4ungroup()
5
6## # A tibble: 9 x 11
7## mpg cyl disp hp drat wt qsec vs am gear carb
8## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
9## 1 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
10## 2 24.4 4 147. 62 3.69 3.19 20 1 0 4 2
11## 3 22.8 4 141. 95 3.92 3.15 22.9 1 0 4 2
12## 4 21 6 160 110 3.9 2.62 16.5 0 1 4 4
13## 5 21 6 160 110 3.9 2.88 17.0 0 1 4 4
14## 6 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1
15## 7 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2
16## 8 14.3 8 360 245 3.21 3.57 15.8 0 0 3 4
17## 9 16.4 8 276. 180 3.07 4.07 17.4 0 0 3 3
比较有ungroup和没有ungroup的结果,大家可以发现,进行取消分组之后,结果中少了“# Groups: cyl [3]”这一行,也就是说明我们取消分组成功了。
建议大家每次使用group_by的时候,总是在进行分组计算或操作之后,马上使用ungroup函数取消分组,在后面需要继续分组的时候再使用group_by。这样做有利于避免混乱,干净利索地完成每一次分组操作而不会出错。事实上目前版本的dplyr中,每次group_by都会覆盖掉之前的分组,也就是如果你在一条语句中出现了两个group_by,那么后面的分组会覆盖掉前面的分组,也就是前面的分组会自动失效。如果你是想要叠加分组,那么可以在group_by函数中进行参数设置,添加“add = T”即可。
分组排序
分组本身只是数据组织形式的改变,不会对数据造成任何变化。我们分组的目的,往往是为了在分组之后对各个组别进行相同的处理。下面我们先举一个分组排序的例子,我们想要查看不同气缸数(cyl)的汽车的马力(hp),挑出最高的三款汽车来看。
1mtcars1 %>%
2group_by(cyl) %>% #根据cyl分组
3arrange(desc(hp)) %>% #根据hp做降序排列
4slice(1:3) %>% #取没组前三个记录
5ungroup() #取消分组
6
7## # A tibble: 9 x 11
8## mpg cyl disp hp drat wt qsec vs am gear carb
9## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
10## 1 30.4 4 95.1 113 3.77 1.51 16.9 1 1 5 2
11## 2 21.4 4 121 109 4.11 2.78 18.6 1 1 4 2
12## 3 21.5 4 120. 97 3.7 2.46 20.0 1 0 3 1
13## 4 19.7 6 145 175 3.62 2.77 15.5 0 1 5 6
14## 5 19.2 6 168. 123 3.92 3.44 18.3 1 0 4 4
15## 6 17.8 6 168. 123 3.92 3.44 18.9 1 0 4 4
16## 7 15 8 301 335 3.54 3.57 14.6 0 1 5 8
17## 8 15.8 8 351 264 4.22 3.17 14.5 0 1 5 4
18## 9 14.3 8 360 245 3.21 3.57 15.8 0 0 3 4
分组过滤
下面我们希望挑选不同气缸数的汽车里面,它们马力能够达到150以上的汽车记录,代码如下:
1mtcars1 %>%
2group_by(cyl) %>%
3filter(hp > 150) %>%
4ungroup()
5
6## # A tibble: 13 x 11
7## mpg cyl disp hp drat wt qsec vs am gear carb
8## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
9## 1 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2
10## 2 14.3 8 360 245 3.21 3.57 15.8 0 0 3 4
11## 3 16.4 8 276. 180 3.07 4.07 17.4 0 0 3 3
12## 4 17.3 8 276. 180 3.07 3.73 17.6 0 0 3 3
13## 5 15.2 8 276. 180 3.07 3.78 18 0 0 3 3
14## 6 10.4 8 472 205 2.93 5.25 18.0 0 0 3 4
15## 7 10.4 8 460 215 3 5.42 17.8 0 0 3 4
16## 8 14.7 8 440 230 3.23 5.34 17.4 0 0 3 4
17## 9 13.3 8 350 245 3.73 3.84 15.4 0 0 3 4
18## 10 19.2 8 400 175 3.08 3.84 17.0 0 0 3 2
19## 11 15.8 8 351 264 4.22 3.17 14.5 0 1 5 4
20## 12 19.7 6 145 175 3.62 2.77 15.5 0 1 5 6
21## 13 15 8 301 335 3.54 3.57 14.6 0 1 5 8
我们可以发现,要达到150的马力,是需要很多气缸的。结果中没有4个气缸的汽车,6个气缸的汽车只有一个,其余全部是8个气缸的汽车。
分组汇总
现在,我们根据不同的气缸数量,看看不同数量的气缸最高能够达到多少马力。
1mtcars1 %>%
2group_by(cyl) %>%
3summarise(hp_max = max(hp)) %>%
4ungroup()
5
6## # A tibble: 3 x 2
7## cyl hp_max
8## <dbl> <dbl>
9## 1 4 113
10## 2 6 175
11## 3 8 335
我们可以看到,4个气缸的汽车最高马力为113,6个为175,而8个气缸则最高可达335。
小结
本章我们讲解了如何使用分组来进行数据的查询和计算。事实上我们学习的操作都非常简单,但是如果能够把这些简单的操作有效组合起来,它的效率是会倍增的。利用分组,我们可以对不同的组别同时进行排序、过滤、汇总等运算,从而高效完成任务。需要谨记的是,建议在分组运算完毕之后,及时取消分组,以免在后面的操作中发生混乱。
——————————————
往期精彩:
使用dplyr进行数据操作(30个实例)
R语言ETL系列:汇总(summarise)
数据揭秘,在中国谁拥有私人飞机
R语言中文社区2018年终文章整理(作者篇)
R语言中文社区2018年终文章整理(类型篇)