R 数据处理(八)

前言

通常,我们读取的数据不可能完全满足我们后续的分析需求,因此需要对读取进来的数据进行处理。

比如,创建一些新的变量或总结,或者只是想重命名变量或重新排列观察结果,以便使数据更易于使用。

在本节及后续几节,我们将介绍如何使用 tidyverse 中的 dplyr 包来对数据进行操作。

我们使用的数据是 2013 年从纽约出发的航班信息。

1 介绍

1.1 准备

在这里我们的重点是介绍 dplyr 包的使用,并使用的 nycflights13 包中的数据来说明 dplyr 的核心思想,同时会加入一些 ggplot2 展示数据的示例,帮助我们理解。

ggplot2 包的详细介绍将会放在后续的 R 绘图系列中。

# 安装 nycflights13 包
install.packages("nycflights13")
# 导入
library(nycflights13)
# 导入 tidyverse
> library(tidyverse)
─ Attaching packages ─────────────────────────────── tidyverse 1.3.0 ─
✓ ggplot2 3.3.3     ✓ purrr   0.3.4
✓ tibble  3.0.4     ✓ dplyr   1.0.2
✓ tidyr   1.1.2     ✓ stringr 1.4.0
✓ readr   1.4.0     ✓ forcats 0.5.0
─ Conflicts ───────────────────────────────── tidyverse_conflicts() ─
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
# 或者只导入 dplyr
> library(dplyr)

请注意导入 tidyverse 时打印的冲突信息,它告诉你 dplyr 会覆盖基本 R 中的某些函数。

如果要在加载 dplyr 后使用这些函数的基本版本,则需要使用其全名 stats::filter()stats::lag()

1.2 nycflights13

为了探索 dplyr 的基本数据操作,我们将使用 nycflights13::flights

此数据包含 2013 年从纽约起飞的所有 336776 架次航班,这些数据来自美国交通统计局。

> flights
# A tibble: 336,776 x 19
    year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier flight
                                                
 1  2013     1     1      517            515         2      830            819        11 UA        1545
 2  2013     1     1      533            529         4      850            830        20 UA        1714
 3  2013     1     1      542            540         2      923            850        33 AA        1141
 4  2013     1     1      544            545        -1     1004           1022       -18 B6         725
 5  2013     1     1      554            600        -6      812            837       -25 DL         461
 6  2013     1     1      554            558        -4      740            728        12 UA        1696
 7  2013     1     1      555            600        -5      913            854        19 B6         507
 8  2013     1     1      557            600        -3      709            723       -14 EV        5708
 9  2013     1     1      557            600        -3      838            846        -8 B6          79
10  2013     1     1      558            600        -2      753            745         8 AA         301
# … with 336,766 more rows, and 8 more variables: tailnum , origin , dest ,
#   air_time , distance , hour , minute , time_hour 

从打印信息可以看出是一个 tibble 类型,而不是 data.frame 类型

每列的类型代表的含义是:

  • int: 代表整数

  • dbl: 代表 double 或者实数

  • chr: 代表字符向量或字符串

  • dttm: 代表日期-时间

还有另外三种没在这些数据中出现的类型

  • lgl: 代表逻辑值

  • fctr: 代表因子,即分类变量

  • date: 代表日期

1.3 dplyr 基础

在这里,我们将介绍五个关键的 dplyr 动词函数,这些函数可帮助您解决绝大多数的数据处理难题

  • filter(): 对值进行筛选
  • arrange(): 对行进行重排
  • select(): 根据变量名提取变量
  • mutate(): 使用现有变量创建新变量
  • summarise(): 将许多值汇总成一个摘要

这些函数都可以与 groupby() 一起使用,groupby() 将每个函数的作用域从对整个数据集进行操作改为对其分组进行操作

所有动词的工作方式相似:

  1. 第一个参数是数据框
  2. 后面的参数使用变量名描述如何处理数据框
  3. 返回的结果是一个新的数据框

将这些属性结合在一起,可以轻松地将多个简单步骤连接在一起,以获得复杂的结果。让我们深入看看这些动词是如何工作的

2 filter

filter() 允许您根据观察值对其进行筛选子集

第一个参数是数据框的名称。第二个和随后的参数是过滤数据框的表达式

例如,我们可以通过以下方式选择 11 日的所有航班

> filter(flights, month == 1, day == 1)
# A tibble: 842 x 19
    year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier flight
                                                
 1  2013     1     1      517            515         2      830            819        11 UA        1545
 2  2013     1     1      533            529         4      850            830        20 UA        1714
 3  2013     1     1      542            540         2      923            850        33 AA        1141
 4  2013     1     1      544            545        -1     1004           1022       -18 B6         725
 5  2013     1     1      554            600        -6      812            837       -25 DL         461
 6  2013     1     1      554            558        -4      740            728        12 UA        1696
 7  2013     1     1      555            600        -5      913            854        19 B6         507
 8  2013     1     1      557            600        -3      709            723       -14 EV        5708
 9  2013     1     1      557            600        -3      838            846        -8 B6          79
10  2013     1     1      558            600        -2      753            745         8 AA         301
# … with 832 more rows, and 8 more variables: tailnum , origin , dest ,
#   air_time , distance , hour , minute , time_hour 

当您运行上面这行代码时,dplyr 执行过滤操作并返回一个新的数据框。

dplyr 函数不会修改其输入,因此如果要保存结果,则需要使用赋值运算符

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

R 要么打印出结果,要么将其保存到变量中。如果你想同时做这两件事,你可以用圆括号括起来

> (dec25 <- filter(flights, month == 12, day == 25))
# A tibble: 719 x 19
    year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier flight
                                                
 1  2013    12    25      456            500        -4      649            651        -2 US        1895
 2  2013    12    25      524            515         9      805            814        -9 UA        1016
 3  2013    12    25      542            540         2      832            850       -18 AA        2243
 4  2013    12    25      546            550        -4     1022           1027        -5 B6         939
 5  2013    12    25      556            600        -4      730            745       -15 AA         301
 6  2013    12    25      557            600        -3      743            752        -9 DL         731
 7  2013    12    25      557            600        -3      818            831       -13 DL         904
 8  2013    12    25      559            600        -1      855            856        -1 B6         371
 9  2013    12    25      559            600        -1      849            855        -6 B6         605
10  2013    12    25      600            600         0      850            846         4 B6         583
# … with 709 more rows, and 8 more variables: tailnum , origin , dest ,
#   air_time , distance , hour , minute , time_hour 

2.1 比较

要有效地使用过滤,您必须知道如何使用比较运算符来选择需要的值

>, >=, <, <=, != ,  ==

注意,上面的筛选参数用的是 == 而不是 =,如果你用错了

> filter(flights, month = 1)
错误: Problem with `filter()` input `..1`.
x Input `..1` is named.
ℹ This usually means that you've used `=` instead of `==`.
ℹ Did you mean `month == 1`?
Run `rlang::last_error()` to see where the error occurred.

就会产生错误。

使用 == 时可能会遇到的另一个常见问题是: 浮点数。

> sqrt(2) ^ 2 == 2
[1] FALSE
> 1 / 49 * 49 == 1
[1] FALSE

计算机使用有限精度算法(显然是不能存储无限多的数字)所以你看到的每个数字都是近似值

我们使用 near() 函数代替 ==

> near(sqrt(2) ^ 2,  2)
[1] TRUE
> near(1 / 49 * 49, 1)
[1] TRUE

2.2 逻辑运算

filter() 的多个参数会以逻辑与的方式连接,而对于其他类型的组合,您需要自己使用布尔操作符:& | !

我们用下面的代码查找所有在 11 月或 12 月起飞的航班

filter(flights, month == 11 | month == 12)

你不能写成

filter(flights, month == (11 | 12))

它会找到等于 11 | 12 的所有月份,这个表达式的结果是 TRUE

在一个数字上下文中(如这里),TRUE 会变成 1,因此它会查找 1 月份的所有航班,而不是 11 月或 12 月。这真是太让人困惑了.

解决这一问题的一个有用的简写就是

x %in% y

返回一个长度等于 x 的逻辑值向量,即 x 中的每一个元素是否出现在 y 中。

我们重写上面的代码

nov_dec <- filter(flights, month %in% c(11, 12))

有时你可以通过摩根定律来简化复杂的子集,如

!(x & y) => !x | !y
!(x | y) => !x & !y

例如,如果您想查找延迟(到达或离开时)不超过两小时的航班,可以使用下面两个过滤器中的任何一个

filter(flights, !(arr_delay > 120 | dep_delay > 120))
filter(flights, arr_delay <= 120, dep_delay <= 120)

R 中也有 &&||,但是不要在这里使用它们

2.3 缺失值

R 的一个重要特性是缺失值,也就是 NA

NA 表示一个未知值,几乎任何涉及未知值的操作也将是未知的

> NA > 5
[1] NA
> 10 == NA
[1] NA
> NA + 10
[1] NA
> NA / 2
[1] NA

最令人困惑的结果是这个

> NA == NA
[1] NA

是不是想不明白,看看下面的例子,也许可以帮助你理解这是为什么

# Let x be Mary's age. We don't know how old she is.
x <- NA

# Let y be John's age. We don't know how old he is.
y <- NA

# Are John and Mary the same age?
x == y
#> [1] NA
# We don't know!

可以使用 is.na() 判断一个值是不是缺失值

> is.na(NA)
[1] TRUE

filter() 仅包含条件为 TRUE 的行;它不包括 FALSENA 值。如果要保留缺失值,需要明确指定

> df <- tibble(x = c(1, NA, 3))
> filter(df, x > 1)
# A tibble: 1 x 1
      x
  
1     3
> filter(df, is.na(x) | x > 1)
# A tibble: 2 x 1
      x
  
1    NA
2     3

2.4 思考练习

  1. 提取下面所有的航班信息
  • 迟到两个或两个多小时
  • 飞往休斯敦(IAHHOU)
  • UnitedAmerican,或 Delta 经营的航班
  • 夏季出发(July, August, September)
  • 延迟到达超过两小时,但未延迟起飞
  • 至少晚点了一小时,其中飞行时间占了超过 30 分钟
  • 午夜至凌晨 6 点之间出发(0-6
  1. 另一个有用的 dplyr 过滤函数是 between(),它有什么作用?您可以使用它来简化解决前面问题的代码吗?

  2. 有多少航班缺失了 dep_time?同时缺少哪些其他变量?想想这些行代表什么?

  3. 为什么 NA ^ 0 不是缺失值?为什么 NA | TRUE 不是缺失值?为什么 FALSE & NA 不是缺失值?你能弄清楚一般规则吗?(NA * 0 是一个棘手的反例)

感谢花花同学的上期参考答案
http://note.youdao.com/s/DPASe3xt

你可能感兴趣的:(R 数据处理(八))