《R数据科学》第3章——dplyr是什么

写在前面

dplyr是R语言中为数不多的,也是最好用的数据清洗R包,这也是hendly团队的核心产品,承载着在数据到绘图或者分析过程的桥梁。其中包含的函数超过100条,值得我们花费很长的时间一步步学习,尤其是统计函数summury,结合许多子函数可以做到很强大的功能,例如:统计数据框中全部数值列的均值,方差等。但是这并不代表这个包没有缺陷,例如处理大数据,如果数据量超过100M以上,就会很慢,此时我们就需要使用data.table来完成对应的操作。之前dplyr团队有说过要使用C语言将dplyr函数重新编写一下,以提高速度,然而好几年过去了仍然没有什么动作。此外tidyfst包是一个可很好实现dplyr功能并且基于data.table编写,速度非常快,但是R包不太成熟,函数也比较少。处理大数据的一般数据清洗功能还是够的。

正文

首先,dplyr包是tidyverse的一个核心R包,关于tidyverse的介绍见前文初学《R数据科学》之——tidyverse是什么。

其次,dplyr包的功能是转化数据,即对数据进行二次加工,将原始数据转化成更容易分析处理的形式,比如:创建新变量或摘要统计量、对变量重命名、对观测值重新排序等。

接下来,重点介绍dplyr的5个核心函数:

  • filter():筛选行;按值筛选观测,类似于Excel中的筛选;

  • arrange():排列列;只是对行进行重新排序,类似于Excel中的排序;可多重排序。

  • select():选择列;按名称选取变量,仅保留需要分析的列(或变量),可调换列位置等;

  • mutate():添加新变量;用现有变量创建新变量,Excel中实现这一目的需要先添加新列,然后在新列中编写新公式;

  • summarize():进行分组摘要;将多个值总结为一个摘要统计量,为dplyr中非常强大的数据统计函数,结合正则表达式可完成大部分统计。

这些函数都可以和 group_by() 函数联合,group_by() 函数可以改变以上每个函数的作用范围,让其从在整个数据集上操作变为在每个分组上分别操作。也就是说,使用的时候先用group_by()函数对整个数据集进行分组,然后对分组后的数据进行操作。

这 5 个函数的工作方式都是相同的:

  • 第一个参数:

    是一个数据框,即变量(列)和观测(行)的矩形集合。

  • 随后的参数:

    用变量名称描述对数据框上的操作。

  • 输出结果:

    是一个新数据框。

接下来对这5个函数进行详细介绍:

1. 用filter()筛选行

(1)filter()函数是基于观测的值筛选出一个观测子集。第一个参数是数据框名称,第二个参数以及随后的参数是用来筛选数据框的表达式。如,筛选出 1 月 1 日的所有航班:

filter(flights, month == 1, day == 1)
# 这里,flights是数据框,“month == 1, day == 1”是筛选条件

(2)如果想保存筛选结果,就需要使用赋值操作符 <-(“Alt”+“-”快捷输入)将结果保存在一个变量中,如:

jan1 <- filter(flights, month == 1, day == 1)

(3)为了有效筛选,需要一些辅助工具,如:

- 比较运算符:>、 >=、 <、 <=、 !=(不等于)和 ==(等于)

- 逻辑运算符:& (与)、|(或)、!(非)。
- 上述示例中多个参数之间是“与”的关系,必须都为TRUE才会输出。
- “month == 11 | month == 12”可简写成“month %in% c(11, 12)”

- 缺失值(NA):用 is.na() 函数确定一个值是否为缺失值,结果为TRUE或FALSE,如果想保留NA,可以添加添加条件“is.na(x)”,这是用的逻辑运算符为|(或)

2. 用arrange()排列行

(1)接受一个数据框和一组作为排序依据的列名(或者更复杂的表达式)作为参数。

arrange(flights, year, month, day)
# flights为数据框,“year, month, day”为一些要排列的列名
# 如果有多个列名,那么就先按前面的列名排,然后在此基础上排后面的列名,也就是说,列名是有顺序的,不能随便写:
# 默认按升序排。

(2)用 desc() 降序排,如

arrange(flights, desc(arr_delay))
# 按arr_delay降序,对观测进行重排

(3)缺失值总是排在最后。

3. 用select()选择列

(1)基于变量名操作,快速生成一个有用的变量子集。

# 按名称选择列
select(flights, year, month, day)

# 选择“year”和“day”之间的所有列(包括“year”和“day”)
select(flights, year:day)

# 选择不在“year”和“day”之间的所有列(不包括“year”和“day”)
select(flights, -(year:day))

(2)可以在 select () 函数中使用一些辅助函数,这些跟Excel中选择名称的规则类似。

- starts_with("abc"):匹配 开头是“abc” 的名称。
- ends_with("xyz"):匹配 结尾是“xyz” 的名称。
- contains("ijk"):匹配 包含“ijk” 的名称。
- matches("(.)\\1"):选择匹配正则表达式的那些变量。这个正则表达式会匹配名称中有重复字符的变量。
- num_range("x", 1:3):匹配 x1、 x2 和 x3。

(3)用 rename() 函数来重命名变量,如:

rename(flights, tail_num = tailnum)
# 将变量tailnum重命名为tail_num

(4) 与 everything() 函数联用,将想要的几个变 量移到数据框开头,如:

select(flights, time_hour, air_time, everything())
# 把 time_hour 和 air_time 移到数据框的开头,其余按原来的顺序呈现。

4. 用mutate()添加新变量

(1)添加的新列在数据集的最后。如:

flights_sml <-
select(flights,year:day,ends_with("delay"),distance,air_time) # 选择列:year、month、day、dep_delay、arr_delay、distance、air_time
mutate(flights_sml,gain = arr_delay - dep_delay,speed = distance / air_time * 60) # 添加新列:gain 和 speed,并排在数据集的最后。

(2)新列一旦创建,就可立即使用。如:

mutate(flights_sml,gain = arr_delay - dep_delay,hours = air_time / 60,gain_per_hour = gain / hours)
# 在创建新列 gain_per_hour 的时候,用到了刚创建的新列 gain 和 hours 。

(3)如果只想保留新变量,可以使用 transmute() 函数,如:

transmute(flights,gain = arr_delay - dep_delay,hours = air_time / 60,gain_per_hour = gain / hours)
# 输出结果中只有3列:gain 、 hours 和 gain_per_hour。

(4)辅助工具

- 算术运算符:+、 -、 *、 /、 ^

- 模运算符:%/%(求整) 和 %%(求余),可以拆分整数。

- 对数函数:log()、 log2() 和 log10()。

- 偏移函数:lead() 返回序列领先值、 lag() 返回序列滞后值。

- 累加和滚动聚合:cumsum() 累加和、 cumprod() 累加积、commin() 累加最小值、 cummax() 累加最大值、cummean() 累加均值 这几个函数对于绘图非常重要

- 逻辑比较:<、 <=、 >、 >= 和 !=

- 排秩:最常用的是min_rank() ,升序排,输出结果是名次,如1 2 3 ... n。

5. 用summarize()进行分组摘要

(1)可以将数据框折叠成一行,如

summarize(flights, delay = mean(dep_delay, na.rm = TRUE))
# 输出为一个值,即所有航班的平均起飞延误时间。

(2)与 group_by() 联用,即在分组基础上进行摘要统计。group_by() 和 summarize() 联用是 dplyr 包最常用的操作之一:分组摘要。如:

by_day <- group_by(flights, year, month, day) # 将所有航班按日期分组,并将结果赋值给by_day
summarize(by_day, delay = mean(dep_delay, na.rm = TRUE)) # 得到每日平均延误时间。
# 结果仅显示4列,即参与分组的列和新列,分别year、 month、 day 和 delay。

(3)用管道(%>%)组合多种操作,如:要研究每个目的地的距离和平均延误时间之间的关系,用目前已学知识写出的代码如下:

by_dest <- group_by(flights, dest) # 将航班按目的地分组,并赋值给by_dest
delay <- summarize(by_dest,count = n(),dist = mean(distance, na.rm = TRUE),delay = mean(arr_delay, na.rm = TRUE)) # 进行摘要统计,计算航班数量、平均距离、平均延误时间,并赋值给delay。
delay <- filter(delay, count > 20, dest != "HNL") # 通过筛选除去噪声点和火奴鲁鲁机场,并赋值给delay。

用管道(%>%)改写上述代码,结果如下,可见代码简化了许多,并省去了中间数据框命名:

delays <- flights %>%
group_by(dest) %>%
summarize(count = n(),dist = mean(distance, na.rm = TRUE),delay = mean(arr_delay, na.rm = TRUE)) %>%
filter(count > 20, dest != "HNL")

(4)用参数“na.rm = TRUE”在计算前去除缺失值,如:

flights %>%
group_by(year, month, day) %>%
summarize(mean = mean(dep_delay, na.rm = TRUE))

(5)用 n() 函数计数,返回当前分组的大小,如:

delays <- not_cancelled %>%
group_by(tailnum) %>% # 按机尾编号进行分组
summarize(delay = mean(arr_delay, na.rm = TRUE),n = n()) # 计算每架飞机的平均延误时间,并计数每架飞机的飞行次数。

用 sum(!is_na()) 函数进行非缺失值的计数。

(6)只使用均值、计数和求和是远远不够的, R 还提供了常见的摘要函数,如:

- 位置度量:median(x) 中位数

- 分散程度度量:sd(x) 标准误差、 IQR(x) 四分位距 和 mad(x) 绝对中位差

- 秩的度量:min(x)、max(x) 和 quantile(x, 0.25) 找出 x 中按从小到大顺序大于前25% 而小于后 75% 的值

- 定位度量:first(x)、 nth(x, 2) 和 last(x)

- 计数:n() 返回当前分组的大小, sum(!is.na(x)) 计算出非缺失值的数量, n_distinct(x) 计算出唯一值的数量,count()

- 逻辑值的计数和比例:sum(x > 10) 找出 x 中 TRUE 的数量, mean(y == 0) 找出x 中 TRUE 的比例。

(7)用 ungroup() 函数取消分组,并回到未分组的数据继续操作,如:

daily %>%
ungroup() %>% # 不再按日期分组
summarize(flights = n()) # 所有航班

6. 分组新变量(和筛选器)

分组也可以与 mutate() 和 filter() 函数结合,以完成非常便捷的操作,如找出每个分组中最差的成员:

flights_sml %>%
group_by(year, month, day) %>% #按日期分组
filter(rank(desc(arr_delay)) < 10) #按arr_delay降序排列,并返回排名,然后筛选排名前10的行

(0)

相关推荐