5.数据转换(一)

数据转换

5.1 简介

可视化是对数据观察的重要工具,但你很少能直接得到你想要的数据格式。通常,需要创建一些新变量或摘要,或者可能只是想重命名变量或重新排列观察值的结果,从而更容易地处理数据。通过使用dplyr包,让新数据集转换成不同数据。

5.1.1 加载包

我们将重点介绍 tidyverse 的另一个核心成员:dplyr,你将学会使用 dplyr 包。我们将使用 nycflights13 包中的数据来进行说明,并使用 ggplot2 帮助我们理解数据。

library(nycflights13)
library(tidyverse)

请注意加载 tidyverse 包时如果显示冲突消息。它告诉你 dplyr 覆盖了基础 R 中的一些函数。如果你想在加载 dplyr 后使用基础包的函数,则需要使用它们的全名:stats::filter()stats::lag()

5.1.2 nycflights13包

为了了解 dplyr 的基本数据操作方法,我们将使用nycflights13::flights数据集。此数据框包含 2013 年所有从纽约市出发的 336,776 次航班。数据来自美国运输统计局,通过?flights查看详细信息。

flights
#> # A tibble: 336,776 x 19
#>    year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
#>   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
#> 1  2013     1     1      517            515         2      830            819
#> 2  2013     1     1      533            529         4      850            830
#> 3  2013     1     1      542            540         2      923            850
#> 4  2013     1     1      544            545        -1     1004           1022
#> 5  2013     1     1      554            600        -6      812            837
#> 6  2013     1     1      554            558        -4      740            728
#> # … with 336,770 more rows, and 11 more variables: arr_delay <dbl>,
#> #   carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
#> #   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

此数据框的显示结果与以往的数据框略有不同:它仅显示适合屏幕的前几行和所有列。(要查看整个数据集,在 RStudio 查看器中打开数据集,可以运行View(flights))。因为它是tibble,所以显示方式不同。

列名称下的字母缩写描述了每个变量的类型:

  • int 代表整数。

  • dbl 代表双精度实数或实数。

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

  • dttm 代表日期时间(日期 + 时间)。

还有其他类型:

  • lgl代表仅包含TRUEFALSE的逻辑向量。

  • fctr 代表因子,R 用它来表示具有固定可能值的分类变量。

  • date 代表日期。

5.1.3 dplyr基础

下面我们将了解五个关键的 dplyr 函数,这些函数可以解决绝大多数数据问题:

  • 按值选取观察值 ( filter())。
  • 重新排列行 ( arrange())。
  • 按名称选择列变量 ( select())。
  • 使用现有变量创建新变量( mutate()) 。
  • 将多个值进行汇总 ( summarise())。

这些都可以与group_by()一起使用,group_by()从对整个数据集进行分组操作。
所有函数工作方式都相似:

  1. 第一个参数是一个数据框。
  2. 后面的参数使用变量名称(不带引号)描述如何处理数据框。
  3. 结果是一个新的数据框。

将这些属性结合在一起,可以轻松地将多个简单的步骤结合,以实现复杂的结果。接下来,让我们详细了解每个方法的使用吧!

5.2 filter()行过滤

filter()根据观测值对观测结果进行子集化。第一个参数是数据框的名称。第二个和后续参数是过滤数据框的表达式。例如,选择 1 月 1 日的所有航班:

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
#>   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
#> 1  2013     1     1      517            515         2      830            819
#> 2  2013     1     1      533            529         4      850            830
#> 3  2013     1     1      542            540         2      923            850
#> 4  2013     1     1      544            545        -1     1004           1022
#> 5  2013     1     1      554            600        -6      812            837
#> 6  2013     1     1      554            558        -4      740            728
#> # … with 836 more rows, and 11 more variables: arr_delay <dbl>, carrier <chr>,
#> #   flight <int>, tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>,
#> #   distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

当运行该行代码时,dplyr 会执行过滤操作并返回一个新的数据框。dplyr 函数不会修改它们输入的数据集,因此如果要保存结果,则需要使用赋值运算符<-进行保存:

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

如果想显示结果的同时将它们保存到一个变量中,可以用括号括起来:

(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
#>   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
#> 1  2013    12    25      456            500        -4      649            651
#> 2  2013    12    25      524            515         9      805            814
#> 3  2013    12    25      542            540         2      832            850
#> 4  2013    12    25      546            550        -4     1022           1027
#> 5  2013    12    25      556            600        -4      730            745
#> 6  2013    12    25      557            600        -3      743            752
#> # … with 713 more rows, and 11 more variables: arr_delay <dbl>, carrier <chr>,
#> #   flight <int>, tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>,
#> #   distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

5.2.1 比较操作符

为了有效地使用过滤方法,需要知道如何使用比较操作符选择您想要的观察结果。R提供了标准比较操作符:>>=<<=!=(不等于)和==(等于)。

注意,最容易犯的错误是将=当成==使用,=是赋值而==是判断两者相等:

filter(flights, month = 1)
#> Error: Problem with `filter()` input `..1`.
#> ✖ Input `..1` is named.
#> ℹ This usually means that you've used `=` instead of `==`.
#> ℹ Did you mean `month == 1`?

注意:在浮点数比较时需要注意,得到的结果可能和你预想的不一样。

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

5.2.2 逻辑运算符

filter()的多个参数将" and "组合在一起是为了将一行都表示输出中,每个表达式必须为真。对于其他类型的组合,可以使用布尔运算符:&是“与”,|是“或”,!是“非”。下图显示了布尔操作的完整集合。

完整的布尔运算集。 `x` 是左边的圆圈,`y` 是右边的圆圈,阴影区域显示了每个操作得到部分。

查找在 11 月或 12 月起飞的所有航班:

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

执行顺序不像英语。你不能写filter(flights, month == (11 | 12)),你可以理解成“查找所有在 11 月或 12 月起飞的航班”,实际上它会查找所有相等的月份,即11 | 12一个计算结果为TRUE的表达式。TRUE就变为一个1,因此这将查找 1 月份的所有航班,而不是 11 月或 12 月。

该问题比较好的简写是x %in% y。这将选择x中的每一个值是否也在y中。我们可以用它来重写上面的代码:

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

有时,您可以通过记住De Morgan’s law(德摩根定律)来简化复杂的子集:!(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 也有&&||。注意在这里不要使用它们!想了解更多可参阅conditional-execution

5.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(x)
#> [1] TRUE

filter()仅过滤条件为TRUE的行;它排除了FALSENA值。如果想保留缺失值,需要明确要求它们:

df <- tibble(x = c(1, NA, 3))
filter(df, x > 1)
#> # A tibble: 1 x 1
#>       x
#>   <dbl>
#> 1     3
filter(df, is.na(x) | x > 1)
#> # A tibble: 2 x 1
#>       x
#>   <dbl>
#> 1    NA
#> 2     3
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容