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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容