[13] 《R数据科学》使用dplyr进行数据转换

一般来说,如果你需要创建一些新变量或者摘要统计量,并且对变量进行重命名或者对观测值进行重新排序,以便数据更容易处理,那么可以用dplyr包来转换数据,并创建一个新的数据集。

说实话dplyr是真的香,Y叔写过一篇比较awk和dplyr的文章,这也坚定了我要学好dplyr的信念。
忘记awk吧,dplyr它不香吗?

准备工作

library(nycflights13)
library(tidyverse)

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
   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>     <dbl>
 1  2013     1     1      517            515         2      830            819        11
 2  2013     1     1      533            529         4      850            830        20
 3  2013     1     1      542            540         2      923            850        33
 4  2013     1     1      544            545        -1     1004           1022       -18
 5  2013     1     1      554            600        -6      812            837       -25
 6  2013     1     1      554            558        -4      740            728        12
 7  2013     1     1      555            600        -5      913            854        19
 8  2013     1     1      557            600        -3      709            723       -14
 9  2013     1     1      557            600        -3      838            846        -8
10  2013     1     1      558            600        -2      753            745         8
# ... with 336,766 more rows, and 10 more variables: carrier <chr>, flight <int>,
#   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
#   minute <dbl>, time_hour <dttm>

dplyr基础

5个dplyr核心函数:
按值筛选观测(filter()
对行进行重新排序(arrange()
按名称选取变量(select()
使用现有变量函数创建新变量(mutate()
将多个值总结为一个摘要统计量(summarize()

此外,这些函数都可以和group_by()函数联合起来用,group_by()函数可以改变以上每个函数的作用范围,让其从整个数据上的操作变为在每个分组上的操作。

使用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 arr_delay
   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>     <dbl>
 1  2013     1     1      517            515         2      830            819        11
 2  2013     1     1      533            529         4      850            830        20
 3  2013     1     1      542            540         2      923            850        33
 4  2013     1     1      544            545        -1     1004           1022       -18
 5  2013     1     1      554            600        -6      812            837       -25
 6  2013     1     1      554            558        -4      740            728        12
 7  2013     1     1      555            600        -5      913            854        19
 8  2013     1     1      557            600        -3      709            723       -14
 9  2013     1     1      557            600        -3      838            846        -8
10  2013     1     1      558            600        -2      753            745         8
# ... with 832 more rows, and 10 more variables: carrier <chr>, flight <int>,
#   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
#   minute <dbl>, time_hour <dttm>

如果运行这行代码,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 arr_delay
   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>     <dbl>
 1  2013    12    25      456            500        -4      649            651        -2
 2  2013    12    25      524            515         9      805            814        -9
 3  2013    12    25      542            540         2      832            850       -18
 4  2013    12    25      546            550        -4     1022           1027        -5
 5  2013    12    25      556            600        -4      730            745       -15
 6  2013    12    25      557            600        -3      743            752        -9
 7  2013    12    25      557            600        -3      818            831       -13
 8  2013    12    25      559            600        -1      855            856        -1
 9  2013    12    25      559            600        -1      849            855        -6
10  2013    12    25      600            600         0      850            846         4
# ... with 709 more rows, and 10 more variables: carrier <chr>, flight <int>,
#   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
#   minute <dbl>, time_hour <dttm>

比较运算符

R提供了一套标准的运算符号:>、>=、<、<=、!=(不等于)、==(等于)。
在R中 = 用 == 来代替,如果使用 = 会出现:

filter(flights,month=1)
#错误: `month` (`month = 1`) must not be named, do you need `==`?

介绍一个令人目瞪狗呆的操作:

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

根号2的平方等于2,以及1/49×49=1,返回的逻辑值都为FALSE,这个原因是计算机不会储存无限位的数,如果想让上面运行为TRUE,需要借助near()

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

逻辑运算符

简单来说,你可以叫它“与(&),或(|),非(!)”
举个例子,找出11月或12月出发的所有航班:

filter(flights,month == 11 | month == 12)
# A tibble: 55,403 x 19
    year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay
   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>     <dbl>
 1  2013    11     1        5           2359         6      352            345         7
 2  2013    11     1       35           2250       105      123           2356        87
 3  2013    11     1      455            500        -5      641            651       -10
 4  2013    11     1      539            545        -6      856            827        29
 5  2013    11     1      542            545        -3      831            855       -24
 6  2013    11     1      549            600       -11      912            923       -11
 7  2013    11     1      550            600       -10      705            659         6
 8  2013    11     1      554            600        -6      659            701        -2
 9  2013    11     1      554            600        -6      826            827        -1
10  2013    11     1      554            600        -6      749            751        -2
# ... with 55,393 more rows, and 10 more variables: carrier <chr>, flight <int>,
#   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
#   minute <dbl>, time_hour <dttm>

当然这个问题有一种简写的方式,利用x %in% y,这会选出x是y中一个值时的所有行:

filter(flights,month %in% c(11,12))
# A tibble: 55,403 x 19
    year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay
   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>     <dbl>
 1  2013    11     1        5           2359         6      352            345         7
 2  2013    11     1       35           2250       105      123           2356        87
 3  2013    11     1      455            500        -5      641            651       -10
 4  2013    11     1      539            545        -6      856            827        29
 5  2013    11     1      542            545        -3      831            855       -24
 6  2013    11     1      549            600       -11      912            923       -11
 7  2013    11     1      550            600       -10      705            659         6
 8  2013    11     1      554            600        -6      659            701        -2
 9  2013    11     1      554            600        -6      826            827        -1
10  2013    11     1      554            600        -6      749            751        -2
# ... with 55,393 more rows, and 10 more variables: carrier <chr>, flight <int>,
#   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
#   minute <dbl>, time_hour <dttm>

有时也可以用德摩根定律对复杂的筛选条件进行简化:!(x&y)等价于!x | !y,!(x | y)等价于!x&!y。例如,筛选出延误时间(到达或出发)不多于2小时的航班:

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

两种方式都可以实现筛选效果。

缺失值

缺失值我们通常用NA(not available,不可用)表示。
如果想要确定一个值是否为缺失值,可以使用is.na(x)函数:

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