简介
学习记录来源于对《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()