一般来说,如果你需要创建一些新变量或者摘要统计量,并且对变量进行重命名或者对观测值进行重新排序,以便数据更容易处理,那么可以用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
网友评论