在 dplyr 中使用 summarize 函数进行数据汇总时,通常要结合分组函数 group_by 一起使用。
1. group_by:分组函数
group_by 一般会和 mean、sum、max、min、median 等函数一起使用,对数据进行分组汇总,可以同时处理多个字段。
library(dplyr)
library(gapminder)
# 按 year 字段分组, 统计 lifeExp 的均值、对 pop 求和
gapminder %>%
group_by(year) %>%
summarize(mean_lifeExp = mean(lifeExp),
total_pop = sum(pop))
# 按 year、continent 字段分组,统计 lifeExp 的中位数、pop 的最大值、gdpPercap 的最小值
gapminder %>%
group_by(year, continent) %>%
summarize(median_lifeExp = median(lifeExp),
max_pop = max(pop),
min_gdpPercap = min(gdpPercap))
2. count:计数函数
count 函数可以直接统计一个或多个字段分组后的个数,默认会新增一个列名为 n 的字段来表示统计结果,可以使用 name 参数重命名该字段,sort = TRUE 会按个数降序排。
# 按 year 分组计数
gapminder %>% count(year)
# 按 year、continent 分组计数,并降序排
gapminder %>% count(year, continent, name = 'cnt', sort = TRUE)
当然也可以使用 group_by 和 summarise 函数实现上述计数的统计,此时需使用 n() 函数,有时候我们需要去重计数,实现类似于 count distinct 的功能,这时可以使用 n_distinct 函数。
# 按 year 分组计数, 与 count 等价
gapminder %>%
group_by(year) %>%
summarise(n = n())
# 按 year、continent 分组计数, 并降序排, 与 count 等价
gapminder %>%
group_by(year, continent) %>%
summarise(cnt = n()) %>%
arrange(desc(cnt))
# 分组去重计数,按 year 分组,去重统计 continent 的个数
# 类似于 select year, count(distinct continent) from table group by year
gapminder %>%
group_by(year) %>%
summarise(n = n_distinct(continent))
3. 排序函数
dplyr 中的排序函数和 SQL 类似,有 row_number、rank 和 dense_rank 三种,特别注意的是 rank 函数,在 dplyr 包中的写法是 min_rank 而不是 rank,其他两个函数的名称和 SQL 一致,三者的区别如下:
- row_number:相同值排序不重复
- dense_rank:相同值排序重复,排序连续
- min_rank:相同值排序重复,排序不连续
library(tibble)
# 新建一个 tibble 数据框
student_df <- tibble(
name = c('张三', '李四', '王五', '赵六', '孙七', '周八', '吴九'),
score = c(85, 83, 96, 92, 96, 95, 92)
)
# row_number 排序, 相同值不会重复
student_df %>%
mutate(asc_order = row_number(score),
desc_order = row_number(desc(score)))
# dense_rank 排序, 相同值重复且排序连续
student_df %>%
mutate(asc_order = dense_rank(score))
# min_rank 排序, 相同值重复且排序不连续
student_df %>%
mutate(asc_order = min_rank(score))
row_number 排序结果:
dense_rank 排序结果:
min_rank 排序结果:
4. slice 系列函数
4.1 slice、slice_head、slice_tail 函数
slice 的中文含义是切片,所以该函数的功能可以理解为从数据框中选择部分数据,使用起来比较简单。
# 第10行
gapminder %>% slice(10)
# 第1000行到最后一行
gapminder %>% slice(1000:n())
# 前5行
gapminder %>% slice_head(n = 5)
# 后5行
gapminder %>% slice_tail(n = 5)
4.2 slice_max、slice_min 函数
分组查询每组的前n个值,是我们统计排行榜数据时经常需要用到的,比如电商中每个品类销量前10的商品。
早期版本的 dplyr 包,是用 top_n 函数来统计最大或最小的前 n 个值,其中 n 为正数表示最大的 n 个值,n 为负数表示最小的 n 个值。
# pop 字段最大的3个
gapminder %>% top_n(pop, n = 3)
# 按 continent 分组,查询每组 pop 字段最大的3个
gapminder %>%
group_by(continent) %>%
top_n(pop, n = 3)
# pop 字段最小的3个
gapminder %>% top_n(pop, n = -3)
最新版本的 dplyr 包,则使用 slice_max、slice_min 来统计最大或最小的前 n 个值,top_n 在之后的版本中会慢慢废弃,所以还是建议大家使用 slice_max 和 slice_min 函数。
和 top_n 函数相比,slice_max、slice_min 默认会排序,其他的则没有区别。
# pop 字段最大的3个, 从大到小排序
gapminder %>% slice_max(pop, n = 3)
# 按 continent 分组,查询每组 pop 字段最大的3个
gapminder %>%
group_by(continent) %>%
slice_max(pop, n = 3)
# pop 字段最小的3个, 从小到大排序
gapminder %>% slice_min(pop, n = 3)
top_n 取 pop 字段最大的前 3 个:
slice_max 取 pop 字段最大的前 3 个,会默认按 pop 值排序:
当然,上述功能,我们也可以结合已经学习过的 mutate、row_number 等函数来实现。
# 分组查询每个continent的前3
gapminder %>%
group_by(continent) %>%
slice_max(pop, n = 3) %>%
arrange(continent, desc(pop))
# 分组查询每个continent的前3, 使用排序函数 row_number 实现
gapminder %>%
group_by(continent) %>%
mutate(rank_order = row_number(desc(pop))) %>%
filter(rank_order <= 3) %>%
select(-rank_order) %>%
arrange(continent, desc(pop))
4.3 slice_sample:抽样函数
早期版本的 dplyr 包,是用 sample_n、 sample_frac 函数来随机抽样的。
# 按个数抽样, 抽 10 个
gapminder %>% sample_n(10)
# 按比例抽样, 抽总体的 10%
gapminder %>% sample_frac(0.1)
最新版本的 dplyr 包,建议大家使用 slice_sample 来进行抽样,而 sample_n、sample_frac 在之后的版本中会慢慢废弃。
# 按个数抽样
gapminder %>% slice_sample(n = 10)
# 按年份分组抽样, 每年随机抽2个样本
gapminder %>%
group_by(year) %>%
slice_sample(n = 2)
# 按比例抽样
gapminder %>% slice_sample(prop = 0.1)
5. lead、lag:偏移函数
# 向前偏移
student_df %>%
mutate(lead_pop = lead(score))
# 向前偏移2个步长
student_df %>%
mutate(lead_pop = lead(score, n = 2))
# 向后偏移
student_df %>%
mutate(lead_pop = lag(score))
向前偏移 1 位,则最后一行 lead_pop 的值为 NA:
向后偏移1位,则第一行 lead_pop 的值为 NA:
下一节,我们会介绍 dplyr 中不同数据框的连接操作,类似于 SQL 中的 join。