数据转化:Dplyr包的学习

整个延安只有我这间窑洞可以听到莫扎特——冼星海

简介

学习记录来源于对《R数据科学》第三章的阅读学习记录。

数据集:2013年从纽约市出发的航班信息

library(nycflights13)
library(dplyr)

数据理解

首先查看flights数据,这里需要注意到的是,flights的格式为tibble,tibble也是一种数据框,不过可以根据屏幕宽度进行显示(在某些窄屏电脑上数据可能会换行):

> 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核心函数:

  • filter():按值筛选观测
  • arrange():对行进行重新排序
  • select():按名称选取变量
  • mutate():使用现有变量的函数创建新变量
  • summarize():创建摘要统计

使用filter()筛选行

一个简单的筛选操作dplyr::filter(flights, month == 1)可以筛选出1月的航班信息:

> dplyr::filter(flights, month == 1)
# A tibble: 27,004 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
 7  2013     1     1      555            600        -5      913            854
 8  2013     1     1      557            600        -3      709            723
 9  2013     1     1      557            600        -3      838            846
10  2013     1     1      558            600        -2      753            745
# ... with 26,994 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>

同时R提供了一套标准的比较运算符:>、>=、<、!=(不等于)和==(等于)以及逻辑运算符:&(与)、|(或)、!(非),通过这套运算符我们可以对数据进行精确的筛选,例如我们需要找出延误时间(到达或出发)不多于2小时的航班,那么我们可以:

# 此处有两种过滤方式
dplyr::filter(flights, arr_delay <= 120, dep_delay <=120)
dplyr::filter(flights, !(arr_delay > 120 | dep_delay > 120))

练习

找出飞往休斯顿(IAH机场或HOU机场)的航班。

# 示例
dplyr::filter(flights, dest == "IAH" | dest == "HOU")

找出夏季出发的航班。

# 示例
dplyr::filter(flights, month %in% c(7,8,9))

课后问题:dplyr包中对筛选有用的另一个函数为between, 其作用是什么?

使用arrange()排列行

arrange()函数的用处就是排序,它接受一个数据框和一组作为排序依据的列名(或者跟复杂的表达式)作为参数,如果列名不止一个,那么就使用后面的列在前面排序的基础上继续排序。

> arrange(flights, year, month, dep_delay)
# A tibble: 336,776 x 19
    year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier flight
   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>     <dbl> <chr>    <int>
 1  2013     1    11     1900           1930       -30     2233           2243       -10 DL        1435
 2  2013     1    29     1703           1730       -27     1947           1957       -10 F9         837
 3  2013     1    12     1354           1416       -22     1606           1650       -44 FL         349
 4  2013     1    21     2137           2159       -22     2232           2316       -44 DL        2155
 5  2013     1    20      704            725       -21     1025           1035       -10 AS          11
 6  2013     1    12     2050           2110       -20     2310           2355       -45 B6         529
 7  2013     1    12     2134           2154       -20        4             50       -46 B6         515
 8  2013     1    14     2050           2110       -20     2329           2355       -26 B6         529
 9  2013     1     4     2140           2159       -19     2241           2316       -35 DL        2155
10  2013     1    11     1947           2005       -18     2209           2230       -21 9E        4033
# ... with 336,766 more rows, and 8 more variables: tailnum <chr>, origin <chr>, dest <chr>,
#   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

使用desc()可以按列进行降序排序(需要注意的是,缺失值NA总会被排在最后):

> arrange(flights, desc(month))
# A tibble: 336,776 x 19
    year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier flight
   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>     <dbl> <chr>    <int>
 1  2013    12     1       13           2359        14      446            445         1 B6         745
 2  2013    12     1       17           2359        18      443            437         6 B6         839
 3  2013    12     1      453            500        -7      636            651       -15 US        1895
 4  2013    12     1      520            515         5      749            808       -19 UA        1487
 5  2013    12     1      536            540        -4      845            850        -5 AA        2243
 6  2013    12     1      540            550       -10     1005           1027       -22 B6         939
 7  2013    12     1      541            545        -4      734            755       -21 EV        3819
 8  2013    12     1      546            545         1      826            835        -9 UA        1441
 9  2013    12     1      549            600       -11      648            659       -11 US        2167
10  2013    12     1      550            600       -10      825            854       -29 B6         605
# ... with 336,766 more rows, and 8 more variables: tailnum <chr>, origin <chr>, dest <chr>,
#   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

练习

如何将缺失值排在最前端?

> arrange(flights, desc(is.na(arr_time)))
# A tibble: 336,776 x 19
    year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier
   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>     <dbl> <chr>  
 1  2013     1     1     2016           1930        46       NA           2220        NA EV     
 2  2013     1     1       NA           1630        NA       NA           1815        NA EV     
 3  2013     1     1       NA           1935        NA       NA           2240        NA AA     
 4  2013     1     1       NA           1500        NA       NA           1825        NA AA     
 5  2013     1     1       NA            600        NA       NA            901        NA B6     
 6  2013     1     2     2041           2045        -4       NA           2359        NA B6     
 7  2013     1     2     2145           2129        16       NA             33        NA UA     
 8  2013     1     2       NA           1540        NA       NA           1747        NA EV     
 9  2013     1     2       NA           1620        NA       NA           1746        NA EV     
10  2013     1     2       NA           1355        NA       NA           1459        NA EV     
# ... with 336,766 more rows, and 9 more variables: flight <int>, tailnum <chr>, origin <chr>,
#   dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

课后问题:哪个航班的飞行时间最长?那个最短?

使用select()选择列

简单来说,select()可以帮助你快速清洁数据,找出你想要的列进行后续分析。

注意,select()可以使用一些辅助函数,

# 按照名称选择列,并且可以搭配使用辅助函数
> select(flights, starts_with("mo"), ends_with("delay"), contains("sche"))
# A tibble: 336,776 x 5
   month dep_delay arr_delay sched_dep_time sched_arr_time
   <int>     <dbl>     <dbl>          <int>          <int>
 1     1         2        11            515            819
 2     1         4        20            529            830
 3     1         2        33            540            850
 4     1        -1       -18            545           1022
 5     1        -6       -25            600            837
 6     1        -4        12            558            728
 7     1        -5        19            600            854
 8     1        -3       -14            600            723
 9     1        -3        -8            600            846
10     1        -2         8            600            745
# ... with 336,766 more rows

之前提到arrange()函数可以排列行,如果需要排列列顺序怎么办呢?select()函数有everything()这个参数的妙用:

> select(flights, time_hour ,air_time, everything())
# A tibble: 336,776 x 19
   time_hour           air_time  year month   day dep_time sched_dep_time dep_delay
   <dttm>                 <dbl> <int> <int> <int>    <int>          <int>     <dbl>
 1 2013-01-01 05:00:00      227  2013     1     1      517            515         2
 2 2013-01-01 05:00:00      227  2013     1     1      533            529         4
 3 2013-01-01 05:00:00      160  2013     1     1      542            540         2
 4 2013-01-01 05:00:00      183  2013     1     1      544            545        -1
 5 2013-01-01 06:00:00      116  2013     1     1      554            600        -6
 6 2013-01-01 05:00:00      150  2013     1     1      554            558        -4
 7 2013-01-01 06:00:00      158  2013     1     1      555            600        -5
 8 2013-01-01 06:00:00       53  2013     1     1      557            600        -3
 9 2013-01-01 06:00:00      140  2013     1     1      557            600        -3
10 2013-01-01 06:00:00      138  2013     1     1      558            600        -2
# ... with 336,766 more rows, and 11 more variables: arr_time <int>,
#   sched_arr_time <int>, arr_delay <dbl>, carrier <chr>, flight <int>, tailnum <chr>,
#   origin <chr>, dest <chr>, distance <dbl>, hour <dbl>, minute <dbl>

练习

学习one_of()参数的运用:

# 示例
> var <- c("year", "month", "day", "dep_delay")
> select(flights, one_of(var))
# A tibble: 336,776 x 4
    year month   day dep_delay
   <int> <int> <int>     <dbl>
 1  2013     1     1         2
 2  2013     1     1         4
 3  2013     1     1         2
 4  2013     1     1        -1
 5  2013     1     1        -6
 6  2013     1     1        -4
 7  2013     1     1        -5
 8  2013     1     1        -3
 9  2013     1     1        -3
10  2013     1     1        -2
# ... with 336,766 more rows

Chevy 指出下列可用辅助函数,大家可以?select自行疯狂了解一波

starts_with(), ends_with(), contains()

matches()

num_range()

one_of()

everything()

使用mutate()添加新变量

mutate()函数的作用是为了解决我们在处理数据框的时候经常会遇到的增加新的列的需求,而新列是现有列的函数。

而由mutate()函数新创建的列,可以在后续的创建中即使使用:

> mutate(select(flights, year:day, ends_with("delay"), distance, air_time),
+        gain = arr_delay - dep_delay,
+        hours = air_time / 60,
+        gain_per_hour = gain / hours)
# A tibble: 336,776 x 10
    year month   day dep_delay arr_delay distance air_time  gain hours gain_per_hour
   <int> <int> <int>     <dbl>     <dbl>    <dbl>    <dbl> <dbl> <dbl>         <dbl>
 1  2013     1     1         2        11     1400      227     9 3.78           2.38
 2  2013     1     1         4        20     1416      227    16 3.78           4.23
 3  2013     1     1         2        33     1089      160    31 2.67          11.6 
 4  2013     1     1        -1       -18     1576      183   -17 3.05          -5.57
 5  2013     1     1        -6       -25      762      116   -19 1.93          -9.83
 6  2013     1     1        -4        12      719      150    16 2.5            6.4 
 7  2013     1     1        -5        19     1065      158    24 2.63           9.11
 8  2013     1     1        -3       -14      229       53   -11 0.883        -12.5 
 9  2013     1     1        -3        -8      944      140    -5 2.33          -2.14
10  2013     1     1        -2         8      733      138    10 2.3            4.35
# ... with 336,766 more rows

如果只是想依据旧有数据创建一个新的data.frame,好的, transmute()满足你:

> transmute(flights,
+           gain = arr_delay - dep_delay,
+           hours = air_time / 60,
+           gain_per_hour = gain / hours)
# A tibble: 336,776 x 3
    gain hours gain_per_hour
   <dbl> <dbl>         <dbl>
 1     9 3.78           2.38
 2    16 3.78           4.23
 3    31 2.67          11.6 
 4   -17 3.05          -5.57
 5   -19 1.93          -9.83
 6    16 2.5            6.4 
 7    24 2.63           9.11
 8   -11 0.883        -12.5 
 9    -5 2.33          -2.14
10    10 2.3            4.35
# ... with 336,766 more rows

另外,创建新变量的多种函数可供你同mutate()函数一同使用,包括有:

  • 算术运算符:+、-、*、/、^
    • x / sum(x)
    • y -mean(y)
  • 模运算符:%/% 和 %%
    • x == y * (x %/% y) + (x %% y)
  • 对数函数:log2 (), log10(), log()
  • 偏移函数:lead()、lag()
  • 累加和滚动聚合:cumsum()、cumprod()、commin()和cummax()
    • 更加深入的需求可以了解RcppRoll包
  • 逻辑比较:<、 <=、 >、 >=和 !=
  • 排秩函数:min_rank()

练习

将dep_time转化为连续性数值,方便阅读理解,即函从午夜开始的分钟数。

> transmute(flights,
+           dep_time_new = (dep_time %/% 100) * 60 + dep_time %% 100 )
# A tibble: 336,776 x 1
   dep_time_new
          <dbl>
 1          317
 2          333
 3          342
 4          344
 5          354
 6          354
 7          355
 8          357
 9          357
10          358
# ... with 336,766 more rows

比较air_time 和 arr_time - dep_time,有什么区别,如何解决。

使用summarize()添加新变量

summarize()函数可以将数据框折叠成一行:

> summarise(flights, delay = mean(dep_delay, na.rm = T))
# A tibble: 1 x 1
  delay
  <dbl>
1  12.6

当然,这个统计是没有什么优越性的,basicmean()函数也可以做到,但是当你结合group_by()的时候,就会发现丝般顺滑。

> by_day <- group_by(flights, year, month, day)
> by_day
# A tibble: 336,776 x 19
# Groups:   year, month, day [365]
    year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier
   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>     <dbl> <chr>  
 1  2013     1     1      517            515         2      830            819        11 UA     
 2  2013     1     1      533            529         4      850            830        20 UA     
 3  2013     1     1      542            540         2      923            850        33 AA     
 4  2013     1     1      544            545        -1     1004           1022       -18 B6     
 5  2013     1     1      554            600        -6      812            837       -25 DL     
 6  2013     1     1      554            558        -4      740            728        12 UA     
 7  2013     1     1      555            600        -5      913            854        19 B6     
 8  2013     1     1      557            600        -3      709            723       -14 EV     
 9  2013     1     1      557            600        -3      838            846        -8 B6     
10  2013     1     1      558            600        -2      753            745         8 AA     
# ... with 336,766 more rows, and 9 more variables: flight <int>, tailnum <chr>, origin <chr>,
#   dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
> summarise(by_day, delay = mean(dep_delay, na.rm = T))
# A tibble: 365 x 4
# Groups:   year, month [?]
    year month   day delay
   <int> <int> <int> <dbl>
 1  2013     1     1 11.5 
 2  2013     1     2 13.9 
 3  2013     1     3 11.0 
 4  2013     1     4  8.95
 5  2013     1     5  5.73
 6  2013     1     6  7.15
 7  2013     1     7  5.42
 8  2013     1     8  2.55
 9  2013     1     9  2.28
10  2013     1    10  2.84
# ... with 355 more rows

使用管道组合多种操作

假设需要研究每个目的地的距离和平均延误时间之间的关系,正常情况下我们需要怎么做?

> by_dest <- group_by(flights, dest)
> delay <- summarise(by_dest,
+                    conuts = n(),
+                    dis = mean(distance, na.rm = T),
+                    delay = mean(arr_delay, na.rm = T)
+ )
> delay
# A tibble: 105 x 4
   dest  conuts   dis  delay
   <chr>  <int> <dbl>  <dbl>
 1 ABQ      254 1826    4.38
 2 ACK      265  199    4.85
 3 ALB      439  143   14.4 
 4 ANC        8 3370   -2.5 
 5 ATL    17215  757.  11.3 
 6 AUS     2439 1514.   6.02
 7 AVL      275  584.   8.00
 8 BDL      443  116    7.05
 9 BGR      375  378    8.03
10 BHM      297  866.  16.9 
# ... with 95 more rows
> delay <- dplyr::filter(delay, count > 20, dest != "NHL")

随后使用ggplot2作图即可,但频繁的创建中间数据是低效的,这里我们可以使用管道来完成一条龙任务:

> delays <- flights %>%
+   group_by(dest) %>%
+   summarise(
+     count = n(),
+     dis = mean(distance, na.rm = T),
+     delay = mean(arr_delay, na.rm = T)
+   ) %>%
+   dplyr::filter(count > 20, dest != "NHL")
> delays
# A tibble: 97 x 4
   dest  count   dis delay
   <chr> <int> <dbl> <dbl>
 1 ABQ     254 1826   4.38
 2 ACK     265  199   4.85
 3 ALB     439  143  14.4 
 4 ATL   17215  757. 11.3 
 5 AUS    2439 1514.  6.02
 6 AVL     275  584.  8.00
 7 BDL     443  116   7.05
 8 BGR     375  378   8.03
 9 BHM     297  866. 16.9 
10 BNA    6333  758. 11.8 
# ... with 87 more rows

管道的重点在于转化的过程,而不是转换的对象,具体的用法可以自己体会。

事实上,group_by()和summarize()的组合类似与reshape2包的melt()函数,详情大家可以参阅《R语言实战》。

缺失值的处理

我们都知道,数据里掺杂着NA值的时候(事实上还有另外几种),NA: 缺失数据;NaN: 无意义的数,比如sqrt(-2);Inf: 正无穷大;-Inf: 负无穷大,会给计算带来无法预料的麻烦,所以在处理数据的时候我们需要去除这些NA值。basic函数na.omit()可以搞定,而is.na()函数也是可以的。

计数

之前的操作里面其实已经包括了计数函数n(),其非常简单,即是对分组的一个数目统计,在很多时候很实用,当然你也可以使用其他方法达到同样的目的:sum(is.na())

常用的摘要函数

善用摘要函数,可以在分组以后对分组数据进行快捷的统计,达到最终的整理状态。

mean()

median()

sd()

mad()

IQR()

第三章使用dplyr进行数据转换学习结束

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

推荐阅读更多精彩内容