该部分学习内容来自《R for Data Science》。
在对数据进行可视化之前我们往往需要进行数据转换以得到可视化所需要的数据内容与格式。这里我们使用dplyr
包操作2013年纽约市的航班起飞数据集(2013)。
准备
这部分我们聚焦于如何使用dplyr
包,除ggplot2
的另一个tidyverse核心成员。我们将使用nyclights13
数据包解释关键的概念并使用ggplot2
帮助理解数据。
# 导入包
library(nycflights13) # 请确保在使用前已经安装好这些包
library(tidyverse)
## Loading tidyverse: ggplot2
## Loading tidyverse: tibble
## Loading tidyverse: tidyr
## Loading tidyverse: readr
## Loading tidyverse: purrr
## Loading tidyverse: dplyr
## Conflicts with tidy packages ----------------------------------------------
## filter(): dplyr, stats
## lag(): dplyr, stats
注意一下你导入tidyverse
包时给出的冲突信息(Conflicts),它告诉你dplyr覆盖了R基础包中的函数。如果你想要在载入tidyverse包后仍然使用这些函数,你需要使用函数的全名stats::filter()和stats::lag()进行调用。
nycflights13
我们将使用nycflights13::flights
来探索dplyr
包基本的数据操作动词。该数据集包含2013年336,776次航班起飞数据,来自美国交通统计局。
flights
## # A tibble: 336,776 x 19
## year month day dep_t~ sched_~ dep_d~ arr_~ sched~ arr_d~ carr~ flig~
##
## 1 2013 1 1 517 515 2.00 830 819 11.0 UA 1545
## 2 2013 1 1 533 529 4.00 850 830 20.0 UA 1714
## 3 2013 1 1 542 540 2.00 923 850 33.0 AA 1141
## 4 2013 1 1 544 545 -1.00 1004 1022 -18.0 B6 725
## 5 2013 1 1 554 600 -6.00 812 837 -25.0 DL 461
## 6 2013 1 1 554 558 -4.00 740 728 12.0 UA 1696
## 7 2013 1 1 555 600 -5.00 913 854 19.0 B6 507
## 8 2013 1 1 557 600 -3.00 709 723 -14.0 EV 5708
## 9 2013 1 1 557 600 -3.00 838 846 - 8.00 B6 79
## 10 2013 1 1 558 600 -2.00 753 745 8.00 AA 301
## # ... with 336,766 more rows, and 8 more variables: tailnum , origin
## # , dest , air_time , distance , hour , minute
## # , time_hour
与基本包显示的普通数据集输出不同,这里适配地显示了在一个屏幕前几行和所有的列(我们可以使用View(flights)
在Rstudio中查看数据集的所有信息。输出显示不同的原因是这个数据集是一个Tibble。Tibbles都是数据框data.frame
,但经过改良以便于更好(在tidyverse
生态中)工作。现在我们不必纠结于这些差异,在后续内容中我们会进行学习。
你可能已经注意到每个列名下面有三到四个字母的缩写。它们描述了每个变量的类型:
-
int
代表整数 -
dbl
代表浮点数或者实数 -
chr
代表字符向量或者字符串 -
dttm
代表日期-时间
还有其他三种数据类型在本部分不会使用到,但后续我们会接触:
-
lgl
代表逻辑向量,只含TRUE
和FALSE
-
fctr
代表因子,R用它来代表含固定可能值的分类变量 -
date
代表日期
dplyr基础
这部分我们学习5个关键的dplyr
函数,它可以让我们解决遇到的大部分数据操作问题:
- 根据值选择观察(记录),
filter()
- 对行重新排序,
arrange()
- 根据名字选择变量,
select()
- 根据已知的变量创建新的变量,
mutate()
- 将许多值塌缩为单个描述性汇总,
summarize()
这些函数都可以通过group_by()
衔接起来,该函数改变上述每个函数的作用域,从操作整个数据集到按组与组操作。这六个函数提供了数据操作语言的动词。
所有的动词工作都非常相似:
- 第一个参数都是数据框
- 随后的参数描述了使用变量名(不加引号)对数据框做什么
- 结果是一个新的数据框
这些属性一起便利地将多个简单步骤串联起来得到一个复杂的操作(结果)。让我们实际来看看这些动词是怎么工作的。
使用filter()过滤行
filter()
允许我们根据观测值来对数据集取子集。第一个参数是数据框的名字,第二和随后的参数是用于过滤数据框的表达式。
比如,我们可以选择所有一月一号的航班:
filter(flights, month == 1, day == 1)
## # A tibble: 842 x 19
## year month day dep_t~ sched_~ dep_d~ arr_~ sched~ arr_d~ carr~ flig~
##
## 1 2013 1 1 517 515 2.00 830 819 11.0 UA 1545
## 2 2013 1 1 533 529 4.00 850 830 20.0 UA 1714
## 3 2013 1 1 542 540 2.00 923 850 33.0 AA 1141
## 4 2013 1 1 544 545 -1.00 1004 1022 -18.0 B6 725
## 5 2013 1 1 554 600 -6.00 812 837 -25.0 DL 461
## 6 2013 1 1 554 558 -4.00 740 728 12.0 UA 1696
## 7 2013 1 1 555 600 -5.00 913 854 19.0 B6 507
## 8 2013 1 1 557 600 -3.00 709 723 -14.0 EV 5708
## 9 2013 1 1 557 600 -3.00 838 846 - 8.00 B6 79
## 10 2013 1 1 558 600 -2.00 753 745 8.00 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_t~ sched_~ dep_d~ arr_~ sched~ arr_d~ carr~ flig~
##
## 1 2013 12 25 456 500 -4.00 649 651 - 2.00 US 1895
## 2 2013 12 25 524 515 9.00 805 814 - 9.00 UA 1016
## 3 2013 12 25 542 540 2.00 832 850 -18.0 AA 2243
## 4 2013 12 25 546 550 -4.00 1022 1027 - 5.00 B6 939
## 5 2013 12 25 556 600 -4.00 730 745 -15.0 AA 301
## 6 2013 12 25 557 600 -3.00 743 752 - 9.00 DL 731
## 7 2013 12 25 557 600 -3.00 818 831 -13.0 DL 904
## 8 2013 12 25 559 600 -1.00 855 856 - 1.00 B6 371
## 9 2013 12 25 559 600 -1.00 849 855 - 6.00 B6 605
## 10 2013 12 25 600 600 0 850 846 4.00 B6 583
## # ... with 709 more rows, and 8 more variables: tailnum , origin
## # , dest , air_time , distance , hour , minute
## # , time_hour
比较
想要有效地过滤,你必须知道怎么利用比较操作符来选择观测值。R提供了标准的比较符:>
,>=
,<=
,!=
和==
。
如果你是初学R,一个常见的错误是用=
而不是==
来检测相等。如果这种情况发生了,你会收到报错信息:
filter(flights, month = 1)
#> Error: `month` (`month = 1`) must not be named, do you need `==`?
另一个你在使用==
时可能遭遇的常见问题是浮点数。下面的结果可能会让你惊掉大牙:
sqrt(2) ^ 2 == 2
## [1] FALSE
1/49 * 49 == 1
## [1] FALSE
逻辑操作符
&
是与,|
是或,!
是非。
下面代码找到在十一月或十二月起飞的所有航班:
filter(flights, month == 11 | month == 12)
## # A tibble: 55,403 x 19
## year month day dep_t~ sched~ dep_del~ arr_~ sche~ arr_d~ carr~ flig~
##
## 1 2013 11 1 5 2359 6.00 352 345 7.00 B6 745
## 2 2013 11 1 35 2250 105 123 2356 87.0 B6 1816
## 3 2013 11 1 455 500 - 5.00 641 651 -10.0 US 1895
## 4 2013 11 1 539 545 - 6.00 856 827 29.0 UA 1714
## 5 2013 11 1 542 545 - 3.00 831 855 -24.0 AA 2243
## 6 2013 11 1 549 600 - 11.0 912 923 -11.0 UA 303
## 7 2013 11 1 550 600 - 10.0 705 659 6.00 US 2167
## 8 2013 11 1 554 600 - 6.00 659 701 - 2.00 US 2134
## 9 2013 11 1 554 600 - 6.00 826 827 - 1.00 DL 563
## 10 2013 11 1 554 600 - 6.00 749 751 - 2.00 DL 731
## # ... with 55,393 more rows, and 8 more variables: tailnum , origin
## # , dest , air_time , distance , hour , minute
## # , time_hour
注意,你不能写成filter(flights, month == 11 | 12)
,(虽然语义上讲的通)对于R而言,它会先计算11|12
得到1
,然后计算month == 1
,这就不是我们需要的了!
解决这种问题的一种有用简写为x %in% y
。这将选择符合x
属于y
的行(x
是y
中的一个值)。我们可以用它重写前面的代码:
nov_dec <- filter(flights, month %in% c(11, 12))
缺失值
NA代表未知值或者称为缺失值,它是能“传染”的,几乎任何涉及未知值的操作都会是一个未知值。
NA > 5
## [1] NA
10 == NA
## [1] NA
NA + 10
## [1] NA
NA / 2
## [1] NA
最让人困惑的结果是这个:
NA == NA
## [1] NA
最简单理解为什么这是TRUE
的方式是带入一点语境:
# 把x看作小明的年龄,我们不知道他多大
x <- NA
# 把y看作小红的年龄,我们不知道她多大
y <- NA
# 小明和小红一样大吗?
x == y
## [1] NA
# 我们不知道
如果你想确定一个值是不是缺失了,使用is.na()
:
is.na(x)
## [1] TRUE
filter()
仅仅会包含条件是TRUE
的行,把是FALSE
或者NA
的行排除。如果你想要保留缺失值,你可以显式地指定:
df <- tibble(x = c(1, NA, 3))
filter(df, x > 1)
## # A tibble: 1 x 1
## x
##
## 1 3.00
filter(df, is.na(x) | x > 1)
## # A tibble: 2 x 1
## x
##
## 1 NA
## 2 3.00
练习
- 寻找满足以下条件的所有航班:
- 有一次大于等于2小时的航班抵达延误
- 飞去Houston(IAH或者HOU)
- 航空公司为United,American或者Delta (应当缩写是UA和DL)
- 在夏天起飞(July,August和September)
- 抵达延误超过两小时,但起飞时间正常
- 起飞时间在午夜到6.a.m之间(包含)
- 另一个有用的dplyr过滤助手是
between()
函数。它是做什么的?你可以使用它简化用于解决前面问题的代码吗? - 有多少航班有一个缺失的
dep_time
?其他缺失的变量有哪些?这些行表示什么呢? - 为什么
NA ^ 0
不是缺失值?为什么NA | TRUE
不是缺失值?为什么FALSE & NA
不是缺失值?你可以弄懂它们的基本原理吗?
练习有关的见解和答案我只发布在博客上(有兴趣学习还是要自己动手和思考下)