R数据科学》学习笔记|Note4:使用dplyr进行数据转换(上
原文链接:
3.1
简介
一般来说,你需要创建一些新变量或者摘要统计量,还可能对变量进行重命名或对观测值进行重新排序,以便数据更容易处理。你将在本章中学会如何进行这些甚至更多操作,本章将教会你如何使用 dplyr 包来转换数据,并介绍一个新的数据集:2013 年从纽约市出发的航班信息。
3.1.1
准备工作
本章将重点讨论如何使用 tidyverse 中的另一个核心 R 包—dplyr 包。我们使 用nycflights13 包中的数据来说明 dplyr 包的核心理念,并使用 ggplot2 来帮助我们理解数据。
1BiocManager::install('nycflights13')
2library(nycflights13)
3library(tidyverse)
3.1.2
nycflights13
为了介绍 dplyr 中的基本数据操作,我们需要使用 nycflights13::flights。这个数据框包含了 2013 年从纽约市出发的所有 336 776 次航班的信息。该数据来自于美国交通统计局,可以使用 ?flights 查看其说明文档:
1> flights
2# A tibble: 336,776 x 19
3 year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay
4
5 1 2013 1 1 517 515 2 830 819 11
6 2 2013 1 1 533 529 4 850 830 20
7 3 2013 1 1 542 540 2 923 850 33
8 4 2013 1 1 544 545 -1 1004 1022 -18
9 5 2013 1 1 554 600 -6 812 837 -25
10 6 2013 1 1 554 558 -4 740 728 12
11 7 2013 1 1 555 600 -5 913 854 19
12 8 2013 1 1 557 600 -3 709 723 -14
13 9 2013 1 1 557 600 -3 838 846 -8
1410 2013 1 1 558 600 -2 753 745 8
15# ... with 336,766 more rows, and 10 more variables: carrier , flight ,
16# tailnum , origin , dest , air_time , distance , hour ,
17# minute , time_hour
这个数据框的输出和我们以前用过的其他数据框有一点差别:只显示了前几行和适合屏幕宽度的几列。(要想看到整个数据集,可以使用 View(flights) 在 RStudio查看器中打开数据集。)
列名下面有一行 3 个或 4 个字母的缩写。它们描述了每个变量的类型。
• int 表示整数型变量。
• dbl 表示双精度浮点数型变量,或称实数。
• chr 表示字符向量,或称字符串。
• dttm 表示日期时间(日期 + 时间)型变量。
还有另外 3 种常用的变量类型,虽然没有在这个数据集中出现,但很快就会在本书后面遇到。
• lgl 表示逻辑型变量,是一个仅包括 TRUE 和 FALSE 的向量。
• fctr 表示因子,R 用其来表示具有固定数目的值的分类变量。
• date 表示日期型变量。
3.1.3
dplyr 基础
本章将学习 5 个 dplyr 核心函数。
• 按值筛选观测(filter())。
• 对行进行重新排序(arrange() )。
• 按名称选取变量(select() )。
• 使用现有变量的函数创建新变量(mutate() )。
• 将多个值总结为一个摘要统计量(summarize())。
这些函数都可以和 group_by() 函数联合起来使用,group_by() 函数可以改变以上每个函数的作用范围,让其从在整个数据集上操作变为在每个分组上分别操作。这 6 个函数构成了数据处理语言的基本操作。
3.2
使用filter() 筛选行
filter() 函数可以基于观测的值筛选出一个观测子集。第一个参数是数据框名称,第二个参数以及随后的参数是用来筛选数据框的表达式。例如,我们可以使用以下代码筛选出 1月 1 日的所有航班:
1> filter(flights, month == 1, day == 1)
2# A tibble: 842 x 19
3 year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay
4
5 1 2013 1 1 517 515 2 830 819 11
6 2 2013 1 1 533 529 4 850 830 20
7 3 2013 1 1 542 540 2 923 850 33
8 4 2013 1 1 544 545 -1 1004 1022 -18
9 5 2013 1 1 554 600 -6 812 837 -25
10 6 2013 1 1 554 558 -4 740 728 12
11 7 2013 1 1 555 600 -5 913 854 19
12 8 2013 1 1 557 600 -3 709 723 -14
13 9 2013 1 1 557 600 -3 838 846 -8
1410 2013 1 1 558 600 -2 753 745 8
15# ... with 832 more rows, and 10 more variables: carrier , flight , tailnum ,
16# origin , dest , air_time , distance , hour , minute ,
17# time_hour
如果运行这行代码,dplyr 就会执行筛选操作,并返回一个新数据框。dplyr 函数从来不修改输入,因此,如果想要保存函数结果,那么你就需要使用赋值操作符 <-:
1jan1 <- filter(flights, month == 1, day == 1)
R 要么输出结果,要么将结果保存在一个变量中。如果想同时完成这两种操作,那么你可以用括号将赋值语句括起来:
1> (dec25 <- filter(flights, month == 12, day == 25))
2# A tibble: 719 x 19
3 year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay
4
5 1 2013 12 25 456 500 -4 649 651 -2
6 2 2013 12 25 524 515 9 805 814 -9
7 3 2013 12 25 542 540 2 832 850 -18
8 4 2013 12 25 546 550 -4 1022 1027 -5
9 5 2013 12 25 556 600 -4 730 745 -15
10 6 2013 12 25 557 600 -3 743 752 -9
11 7 2013 12 25 557 600 -3 818 831 -13
12 8 2013 12 25 559 600 -1 855 856 -1
13 9 2013 12 25 559 600 -1 849 855 -6
1410 2013 12 25 600 600 0 850 846 4
15# ... with 709 more rows, and 10 more variables: carrier , flight , tailnum ,
16# origin , dest , air_time , distance , hour , minute ,
17# time_hour
3.2.1
比较运算符
为了有效地进行筛选,你必须知道如何使用比较运算符来选择观测。R 提供了一套标准的比较运算符:>、>=、<、<=、!=(不等于)和 ==(等于)。当开始使用 R 时,最容易犯的错误就是使用 = 而不是 == 来测试是否相等。
在使用 == 进行比较时,你可能还会遇到另一个常见问题:浮点数。下面的结果可能会令你目瞪口呆:
1> sqrt(2) ^ 2 == 2
2[1] FALSE
3> #> [1] FALSE
4> 1/49 * 49 == 1
5[1] FALSE
计算机使用的是有限精度运算(显然无法存储无限位的数),因此请记住,你看到的每个数都是一个近似值。比较浮点数是否相等时,不能使用 ==,而应该使用 near():
1near(sqrt(2) ^ 2, 2)
2#> [1] TRUE
3near(1 / 49 * 49, 1)
4#> [1] TRUE
3.2.2
逻辑运算符
filter() 中的多个参数是由“与”组合起来的:每个表达式都必须为真才能让一行观测包含在输出中。如果要实现其他类型的组合,你需要使用布尔运算符:& 表示“与”、| 表示“或”、! 表示“非”。下图给出了布尔运算的完整集合。
以下代码可以找出 11 月或 12 月出发的所有航班:
1filter(flights, month == 11 | month == 12)
表达式中的运算顺序和语言中的是不一样的。你不能写成 filter(flights, month == 11 |12) 这种形式。这种形式的文字翻译确实是“找出 11 月或 12 月出发的所有航班”,但在代码中则不是这个意思,代码中的含义是找出所有出发月份为 11 | 12 的航班。11 | 12 这个逻辑表达式的值为 TRUE,在数字语境中(如本例),TRUE 就是 1,所以这段代码找出的不是 11 月或 12 月出发的航班,而是 1 月出发的所有航班。
这种问题有一个有用的简写形式:x %in% y。这会选取出 x 是 y 中的一个值时的所有行。我们可以使用这种形式重写上面的代码:
1nov_dec <- filter(flights, month %in% c(11, 12))
有时你可以使用德摩根定律将复杂的筛选条件进行简化:!(x & y)等价于
!x | !y、!(x |y)等价于 !x & !y。例如,如果想要找出延误时间(到达或出发)不多于 2 小时的航班,那么使用以下两种筛选方式均可:
1filter(flights, !(arr_delay > 120 | dep_delay > 120))
2filter(flights, arr_delay <= 120, dep_delay <= 120)
3.2.3
缺失值
R 的一个重要特征使得比较运算更加复杂,这个特征就是缺失值,或称 NA(not available,不可用)。NA 表示未知的值,因此缺失值是“可传染的”。如果运算中包含了未知值,那么运算结果一般来说也是个未知值:
1NA > 5
2#> [1] NA
310 == NA
4#> [1] NA
5NA + 10
6#> [1] NA
7NA / 2
8#> [1] NA
最令人费解的是以下这个结果:
1NA == NA
2#> [1] NA
要想理解为什么会这样,最容易的方式是加入一点背景知识:
1# 令x为Mary的年龄。我们不知道她有多大。
2x <- NA
3# 令y为John的年龄。我们不知道他有多大。
4y <- NA
5# John和Mary的年龄是相同的吗?
6x == y
7#> [1] NA
8# 我们不知道!
如果想要确定一个值是否为缺失值,可以使用 is.na() 函数:
1> x <- NA
2> is.na(x)
3[1] TRUE
filter() 只能筛选出条件为 TRUE 的行;它会排除那些条件为 FALSE 和 NA 的行。如果想保留缺失值,可以明确指出:
1> df <- tibble(x = c(1, NA, 3))
2> filter(df, x > 1)
3# A tibble: 1 x 1
4 x
5
61 3
7> filter(df, is.na(x) | x > 1)
8# A tibble: 2 x 1
9 x
10
111 NA
122 3
3.3
使用arrange()排列行
arrange() 函数的工作方式与 filter() 函数非常相似,但前者不是选择行,而是改变行的顺序。它接受一个数据框和一组作为排序依据的列名(或者更复杂的表达式)作为参数。如果列名不只一个,那么就使用后面的列在前面排序的基础上继续排序:
1arrange(flights, year, month, day)
1> arrange(flights, year, month, day)
2# A tibble: 336,776 x 19
3 year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay
4
5 1 2013 1 1 517 515 2 830 819 11
6 2 2013 1 1 533 529 4 850 830 20
7 3 2013 1 1 542 540 2 923 850 33
8 4 2013 1 1 544 545 -1 1004 1022 -18
9 5 2013 1 1 554 600 -6 812 837 -25
10 6 2013 1 1 554 558 -4 740 728 12
11 7 2013 1 1 555 600 -5 913 854 19
12 8 2013 1 1 557 600 -3 709 723 -14
13 9 2013 1 1 557 600 -3 838 846 -8
1410 2013 1 1 558 600 -2 753 745 8
15# ... with 336,766 more rows, and 10 more variables: carrier , flight ,
16# tailnum , origin , dest , air_time , distance , hour ,
17# minute , time_hour
使用 desc() 可以按列进行降序排序:
1> arrange(flights, desc(arr_delay))
2# A tibble: 336,776 x 19
3 year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay
4
5 1 2013 1 9 641 900 1301 1242 1530 1272
6 2 2013 6 15 1432 1935 1137 1607 2120 1127
7 3 2013 1 10 1121 1635 1126 1239 1810 1109
8 4 2013 9 20 1139 1845 1014 1457 2210 1007
9 5 2013 7 22 845 1600 1005 1044 1815 989
10 6 2013 4 10 1100 1900 960 1342 2211 931
11 7 2013 3 17 2321 810 911 135 1020 915
12 8 2013 7 22 2257 759 898 121 1026 895
13 9 2013 12 5 756 1700 896 1058 2020 878
1410 2013 5 3 1133 2055 878 1250 2215 875
15# ... with 336,766 more rows, and 10 more variables: carrier , flight ,
16# tailnum , origin , dest , air_time , distance , hour ,
17# minute , time_hour
缺失值总是排在最后:
1> df <- tibble(x = c(5, 2, NA))
2> arrange(df, x)
3# A tibble: 3 x 1
4 x
5
61 2
72 5
83 NA
9> arrange(df, desc(x))
10# A tibble: 3 x 1
11 x
12
131 5
142 2
153 NA
— END —
往期 · 推荐
《R数据科学》学习笔记|Note2:使用ggplot2进行数据可视化(上)