翻译自:??dplyr->vignettes->dplyr::dplyr——Introduction to dplyr。
当用数据工作时,你必须:
1. 想出你想做什么
2. 用计算机程序结构描述那些工作
3. 执行程序
Dplyr包使这些步骤变得更快更容易:
1. 通过约束你的选择,它可以帮助你思考数据操作中的难题。
2. 它提供简单的“动词”、以及相应的大量常规数据计算任务的方程,来帮助你将你的想法转换为代码。
3. 它使用了高效率的后端,所以你花在等待电脑响应的时间变少了。
这个文档向你介绍了dplyr的基本工具集,并展示了怎样将它们应用于数据框。也可使用dplyr的扩展包dbplyr包来处理数据库。一旦你已经安装,可以读入vignetter(“dbplyr”)(这条语句等同于??dbplyr)来学习更多知识。
数据:nycflights13包
为了探索dplyr包的基本数据操作动词,我们将使用nycflights13:flights数据集。这个数据集包含了2013年从纽约起飞的336776次航班。数据来源于美国
注:在首次使用nycflights13包时,需要 :
install.packages("nycflight13")
我们可以查看一下数据集内容:
> library(nycflights13)
> dim(flights)
[1] 336776 19
> class(flights)
[1] "tbl_df" "tbl" "data.frame"
[2] > names(flights)
[3] [1] "year" "month" "day"
[4] "dep_time" "sched_dep_time" "dep_delay"
[7] "arr_time" "sched_arr_time" "arr_delay"
[10] "carrier" "flight" "tailnum"
[13] "origin" "dest" "air_time"
[16] "distance" "hour" "minute"
[19] "time_hour"
> flights
# A tibble: 336,776 x 19
year month day dep_time sched_dep_time dep_delay arr_time
1 2013 1 1 517 515 2 830
2 2013 1 1 533 529 4 850
3 2013 1 1 542 540 2 923
4 2013 1 1 544 545 -1 1004
5 2013 1 1 554 600 -6 812
6 2013 1 1 554 558 -4 740
7 2013 1 1 555 600 -5 913
8 2013 1 1 557 600 -3 709
9 2013 1 1 557 600 -3 838
10 2013 1 1 558 600 -2 753
# ... with 336,766 more rows, and 12 more variables:
# sched_arr_time , arr_delay , carrier ,
# flight , tailnum , origin , dest ,
# air_time , distance , hour , minute ,
# time_hour
注意nycflights13::flights是一个tibble数据类型,是数据框(data.frame)类型的重新塑造。它对于大型数据集特别有用,因为它仅仅输出最前面几行的数据(节省时间)。你可以从这里
单表动词
Dplyr目的是为每一个基本数据操作动作提供一个函数:
1. filter()根据它们的值选择实例。
2. arrange()将实例重新排列。
3. select()和rename():根据它们的变量名选择变量。
4. mutate()和transmute():添加新的变量,这些变量是现有变量的函数。
5. summarise():将多个值压缩为一个值。
6. sample_n()和sample_frac():获得一个随机样本。
fliter():过滤行
fliter()允许你从数据框中选择出一个多行子集。与所有的单表动词(single verbs)一样,它的第一个参数就是tibble(或数据框)。第二个和随后的参数引用该数据框中的变量,选择表达式为真的行。
例如:选择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
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 , flight , tailnum ,
# origin , dest , air_time , distance , hour , minute ,
# time_hour
大致与下述基本R代码作用相同:
> flights[flights$month==1&flights$day==1,]
arrange():行排列
Arrange()的功能与filter()相似,但除了过滤和选择行之外,它还会对其进行排列。它需要一个数据框和一组列名称(或者更复杂的表达式)来进行排序。如果你使用了不止一个列名,每一个附加的列将被打断插入先前的列值当中。
> arrange(flights,year,month,day)
# A tibble: 336,776 x 19
year month day dep_time sched_dep_time dep_delay arr_time
1 2013 1 1 517 515 2 830
2 2013 1 1 533 529 4 850
3 2013 1 1 542 540 2 923
4 2013 1 1 544 545 -1 1004
5 2013 1 1 554 600 -6 812
6 2013 1 1 554 558 -4 740
7 2013 1 1 555 600 -5 913
8 2013 1 1 557 600 -3 709
9 2013 1 1 557 600 -3 838
10 2013 1 1 558 600 -2 753
# ... with 336,766 more rows, and 12 more variables:
# sched_arr_time , arr_delay , carrier ,
# flight , tailnum , origin , dest ,
# air_time , distance , hour , minute ,
# time_hour
使用desc()对一个列进行降序排列。
> arrange(flights,desc(arr_delay))
# A tibble: 336,776 x 19
year month day dep_time sched_dep_time dep_delay arr_time
1 2013 1 9 641 900 1301 1242
2 2013 6 15 1432 1935 1137 1607
3 2013 1 10 1121 1635 1126 1239
4 2013 9 20 1139 1845 1014 1457
5 2013 7 22 845 1600 1005 1044
6 2013 4 10 1100 1900 960 1342
7 2013 3 17 2321 810 911 135
8 2013 7 22 2257 759 898 121
9 2013 12 5 756 1700 896 1058
10 2013 5 3 1133 2055 878 1250
# ... with 336,766 more rows, and 12 more variables:
# sched_arr_time , arr_delay , carrier ,
# flight , tailnum , origin , dest ,
# air_time , distance , hour , minute ,
# time_hour
select():选择列
你经常需要处理有很多列的巨大数据集,可实际上你感兴趣的只有几行。select()使你能够快速聚焦在有用的数据子集上,通常该操作只用于数值型变量:
> select(flights,year,month,day)
# A tibble: 336,776 x 3
year month day
1 2013 1 1
2 2013 1 1
3 2013 1 1
4 2013 1 1
5 2013 1 1
6 2013 1 1
7 2013 1 1
8 2013 1 1
9 2013 1 1
10 2013 1 1
# ... with 336,766 more rows
> select(flights,year:day)
# A tibble: 336,776 x 3
year month day
1 2013 1 1
2 2013 1 1
3 2013 1 1
4 2013 1 1
5 2013 1 1
6 2013 1 1
7 2013 1 1
8 2013 1 1
9 2013 1 1
10 2013 1 1
# ... with 336,766 more rows
> select(flights,-(year:day))
# A tibble: 336,776 x 16
dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay
1 517 515 2 830 819 11
2 533 529 4 850 830 20
3 542 540 2 923 850 33
4 544 545 -1 1004 1022 -18
5 554 600 -6 812 837 -25
6 554 558 -4 740 728 12
7 555 600 -5 913 854 19
8 557 600 -3 709 723 -14
9 557 600 -3 838 846 -8
10 558 600 -2 753 745 8
# ... with 336,766 more rows, and 10 more variables: carrier ,
# flight , tailnum , origin , dest ,
# air_time , distance , hour , minute ,
# time_hour
你可以在select()中使用许多辅助函数,例如starts_with(),ends_with(),matches(),contains()。这些函数可以让你快速匹配符合某些条件的巨大的变量块。输入?Select()可以了解更多详细资料。
你可以使用select()和实名参数来重新命名变量:
> select(flights,tail_num=tailnum)
# A tibble: 336,776 x 1
tail_num
1 N14228
2 N24211
3 N619AA
4 N804JB
5 N668DN
6 N39463
7 N516JB
8 N829AS
9 N593JB
10 N3ALAA
# ... with 336,766 more rows
但是由于select()将所有没有明确提到的变量都删除了,所以不是很有用。因而,我们可以使用rename()来进行变量重命名:
> rename(flights,tail_num=tailnum)
# A tibble: 336,776 x 19
year month day dep_time sched_dep_time dep_delay arr_time
1 2013 1 1 517 515 2 830
2 2013 1 1 533 529 4 850
3 2013 1 1 542 540 2 923
4 2013 1 1 544 545 -1 1004
5 2013 1 1 554 600 -6 812
6 2013 1 1 554 558 -4 740
7 2013 1 1 555 600 -5 913
8 2013 1 1 557 600 -3 709
9 2013 1 1 557 600 -3 838
10 2013 1 1 558 600 -2 753
# ... with 336,766 more rows, and 12 more variables:
# sched_arr_time , arr_delay , carrier ,
# flight , tail_num , origin , dest ,
# air_time , distance , hour , minute ,
# time_hour
mutate():添加新列
除了选择现有列的集合之外,添加新列通常也很有用,这些新列是现有列的函数。这个工作由mutate()完成:
> mutate(flights,gain=arr_delay-dep_delay,speed=distance/air_time*60)
# A tibble: 336,776 x 21
year month day dep_time sched_dep_time dep_delay arr_time
1 2013 1 1 517 515 2 830
2 2013 1 1 533 529 4 850
3 2013 1 1 542 540 2 923
4 2013 1 1 544 545 -1 1004
5 2013 1 1 554 600 -6 812
6 2013 1 1 554 558 -4 740
7 2013 1 1 555 600 -5 913
8 2013 1 1 557 600 -3 709
9 2013 1 1 557 600 -3 838
10 2013 1 1 558 600 -2 753
# ... with 336,766 more rows, and 14 more variables:
# sched_arr_time , arr_delay , carrier ,
# flight , tailnum , origin , dest ,
# air_time , distance , hour , minute ,
# time_hour , gain , speed
Dplyr::mutate()与基础函数transform()相似,但是允许你引用刚刚创建的列:
> mutate(flights,gain=arr_delay-dep_delay,gain_per_hour=gain/(air_time/60))
# A tibble: 336,776 x 21
year month day dep_time sched_dep_time dep_delay arr_time
1 2013 1 1 517 515 2 830
2 2013 1 1 533 529 4 850
3 2013 1 1 542 540 2 923
4 2013 1 1 544 545 -1 1004
5 2013 1 1 554 600 -6 812
6 2013 1 1 554 558 -4 740
7 2013 1 1 555 600 -5 913
8 2013 1 1 557 600 -3 709
9 2013 1 1 557 600 -3 838
10 2013 1 1 558 600 -2 753
# ... with 336,766 more rows, and 14 more variables:
# sched_arr_time , arr_delay , carrier ,
# flight , tailnum , origin , dest ,
# air_time , distance , hour , minute ,
# time_hour , gain , gain_per_hour
如果你仅仅只想保留新的变量,使用transmute():
> transmute(flights,gain=arr_delay-dep_delay,gain_per_hour=gain/(air_time/60))
# A tibble: 336,776 x 2
gain gain_per_hour
1 9 2.378855
2 16 4.229075
3 31 11.625000
4 -17 -5.573770
5 -19 -9.827586
6 16 6.400000
7 24 9.113924
8 -11 -12.452830
9 -5 -2.142857
10 10 4.347826
# ... with 336,766 more rows
summarise():归纳值
最后一个动词是summarise(),它将一个数据框折叠为一个简单汇总集。
> summarise(flights,delay=mean(dep_delay,na.rm = TRUE))
# A tibble: 1 x 1
delay
1 12.63907
在我们学习下面的group by()之前,它并不是很有用。
Sample_n()和sample_frac():随机选取行样本
你可以使用sample()和sample_frac()获得一个行的随机样本。使用sample_n()可选择固定的行数,sample_frac()可选择占总行数固定比例的行数。
> sample_n(flights,10)
# A tibble: 10 x 19
year month day dep_time sched_dep_time dep_delay arr_time
1 2013 11 18 901 903 -2 1216
2 2013 3 9 2106 2110 -4 2149
3 2013 8 27 1713 1711 2 1830
4 2013 10 3 2312 2159 73 9
5 2013 5 26 1803 1720 43 2104
6 2013 2 24 558 600 -2 715
7 2013 7 8 956 959 -3 1231
8 2013 6 28 846 815 31 1026
9 2013 6 21 901 900 1 1116
10 2013 4 27 1224 1130 54 1337
# ... with 12 more variables: sched_arr_time , arr_delay ,
# carrier , flight , tailnum , origin , dest ,
# air_time , distance , hour , minute ,
# time_hour
> sample_frac(flights,0.01)
# A tibble: 3,368 x 19
year month day dep_time sched_dep_time dep_delay arr_time
1 2013 12 20 1134 1135 -1 1334
2 2013 2 10 624 625 -1 853
3 2013 12 4 1814 1800 14 1952
4 2013 7 23 725 735 -10 1003
5 2013 10 20 959 1000 -1 1054
6 2013 2 8 632 630 2 852
7 2013 3 15 1545 1435 70 1837
8 2013 3 3 1924 1930 -6 2053
9 2013 10 3 1559 1559 0 1814
10 2013 4 7 1642 1645 -3 1745
# ... with 3,358 more rows, and 12 more variables: sched_arr_time ,
# arr_delay , carrier , flight , tailnum ,
# origin , dest , air_time , distance , hour ,
# minute , time_hour
使用replace=TRUE时为有放回的取样(即有可能重复取样)。如果需要,可以用weight参数来对取样的数据进行权重设置。
共性
你可能已经注意到,所有这些动词的语法和功能都非常相似:
(1)第一个参数是一个数据框
(2)后面的参数描述对数据框做些什么。你可以直接指定数据框中的列而不需要$.
(3)结果为一个新的数据框。
将这些属性组合在一起,就可以很容易地将多个简单步骤组合在一起,从而实现一个复杂的结果。
这五组函数提供了数据操作的基本语言。基本上,你可以仅仅用这五个有用的方法修剪一个简洁的数据框:你可以对行进行排列(arrange()),挑选出需要观察的或感兴趣的变量(filter()或select()),添加新的变量且这些变量是现有变量的函数(mutate()),或者折叠许多值获得一个综述值(summarise())。该语言的剩余部分为这五个函数在不同数据类型中的应用。例如,我将要讨论这些函数怎样处理分组数据。
操作模式
Dplyr动词可以根据它们所完成的操作类型进行分类(我们有时会说是它们的语义,也就是它们的含义)。最重要和最有用的区别在分组和未分组操作之间。另外,领会select()和mutate()之间的差异是非常有帮助的。
分组操作
Dplyr动词本身非常有用,但你把它们应用到一个数据集中已分组的观测集时,它们会变得更加强大。在dplyr中,你可以使用group_by()函数来完成这一操作,它将一个数据集分解为指定的行组。然后当你把上面的动词应用到结果对象上时,它们就会被自动“分组”应用。
*分组select()和不分组select()一样,除了总是保留分组变量。
*分组arrange()和不分组的相同,除非你设置by_group=TRUE,在这种情况下,它会首先对分组变量进行排序。
*mutate()和filter()非常适合与窗口函数(像rank()或mix(x)==x)一起使用,窗口函数在vignette(“window—function”)中有详细描述。
*sample_n和sample_frac()对每个组使用指定的行数/比例值(分数)进行抽样。
*summarise()对每个组计算汇总值。
在接下来的例子中,我们将完整的数据集分割为一些单独部分,然后对每一部分进行汇总,计算航班的数量(count=()),计算平均距离(dist=mean(distance,na.rm=TRUE)),计算平均延迟时间(delay=mean(arr_delay,na.rm=TRUE))。然后我们使用ggplot2展示这些结果。
library(dplyr)
library(nycflights13)
library(ggplot2)
by_tailnum
delay
count=n(),
dist=mean(distance,na.rm = TRUE),
delay=mean(arr_delay,na.rm = TRUE))
delay20,dist<2000)
#有趣的是,一个飞机的平均延时时间与平均飞行距离之间几乎无关。
ggplot(delay,aes(dist,delay))+
+ geom_point(aes(size=count),alpha=1/2)+
+ geom_smooth()+
+ scale_size_area()
你将summarise()和聚合函数一起使用,输入一个向量,返回一个单值。R基础包中有很多这样函数,例如:min(),max(),mean(),sum(),sd(),median(),IQR()等。Dply包也提供了几个:
n():目前每个分组观测值得数量
n_distinct(x):x中不重复值的数量,与length(unique())作用相同。
First(x)、last(x)、nth(x)——它们的作用与x[1]、x[length(x)]、x[n]相似,但是如果缺少了值,就可以对结果进行更多的控制。
例如,可以用这些函数找出去每一个可能目的地的飞机数量和航班数量。
> destinations
> summarise(destinations,
planes=n_distinct(tailnum),
flights+ =n()
)
# A tibble: 105 x 3
dest planes flights
1 ABQ 108 254
2 ACK 58 265
3 ALB 172 439
4 ANC 6 8
5 ATL 1180 17215
6 AUS 993 2439
7 AVL 159 275
8 BDL 186 443
9 BGR 46 375
10 BHM 45 297
# ... with 95 more rows
当你使用多个变量进行分组操作后,每汇总一个分组都会删去相应的分组等级。这使我们可以很容易地对数据集进行逐步的整合:
> daily
> per_day per_day
# A tibble: 365 x 4
# Groups: year, month [?]
year month day flights
1 2013 1 1 842
2 2013 1 2 943
3 2013 1 3 914
4 2013 1 4 915
5 2013 1 5 720
6 2013 1 6 832
7 2013 1 7 933
8 2013 1 8 899
9 2013 1 9 902
10 2013 1 10 932
# ... with 355 more rows
> per_month
> per_month
# A tibble: 12 x 3
# Groups: year [?]
year month flights
1 2013 1 27004
2 2013 2 24951
3 2013 3 28834
4 2013 4 28330
5 2013 5 28796
6 2013 6 28243
7 2013 7 29425
8 2013 8 29327
9 2013 9 27574
10 2013 10 28889
11 2013 11 27268
12 2013 12 28135
> per_year
> per_year
# A tibble: 1 x 2
year flights
1 2013 336776
但是如果你像这样逐步整合汇总时需要小心:这对求和(sums)和汇总数量(counts)是可以的,但是你需要考虑加权的均值和方差(对于中位数来说这是不可能做到的)。
选择操作
dplyr的一个吸引人的特性是你可以从tibble中引用一些列,就好像它们是常规变量一样。但是,引用无修饰列名(bare column names)的语法一致性隐藏了变量之间的语义差异。提供给select()函数的列名与提供给mutate()函数的列名的含义不同。
选择操作会预估列名和位置。因此,当你使用select()调用基本位置变量名时,实际上代表了它们自己在tibble中的位置。下面的调用与dplyr的方法完全相同:
> #'year'代表数字1
> select(flights,year)
# A tibble: 336,776 x 1
year
1 2013
2 2013
3 2013
4 2013
5 2013
6 2013
7 2013
8 2013
9 2013
10 2013
# ... with 336,766 more rows> select(flights,1)# A tibble: 336,776 x 1
> select(flights,1)
year
1 2013
2 2013
3 2013
4 2013
5 2013
6 2013
7 2013
8 2013
9 2013
10 2013
# ... with 336,766 more rows
同样的,你也无法从周围上下文中引用与列名相同的变量。例如下面的例子,select中的year仍代表1,而不是5。
> year
> select(flights,year)
# A tibble: 336,776 x 1
year
1 2013
2 2013
3 2013
4 2013
5 2013
6 2013
7 2013
8 2013
9 2013
10 2013
# ... with 336,766 more rows
一个非常有用的微妙之处是:只可以使用无修饰列名去选择调用像c(year,month,day)或者year:day这样的句子。在其他所有例子中,若数据框的列没有放在列引用位置(包裹在函数中),允许你在辅助选择中引用上下文变量:
> year
> select(flights,starts_with(year))
# A tibble: 336,776 x 2
dep_time dep_delay
1 517 2
2 533 4
3 542 2
4 544 -1
5 554 -6
6 554 -4
7 555 -5
8 557 -3
9 557 -3
10 558 -2
# ... with 336,766 more rows
这些语言通常非常直观,但要注意细微的差异:
> year
> select(flights,year,identity(year))
# A tibble: 336,776 x 2
year sched_dep_time
1 2013 515
2 2013 529
3 2013 540
4 2013 545
5 2013 600
6 2013 558
7 2013 600
8 2013 600
9 2013 600
10 2013 600
# ... with 336,766 more rows
第一个参数year代表它自己的位置1,第二个参数year会在周围上下文中进行评估,它表示数字5,即位置5。
长期以来,select()仅仅用来理解列的位置。从dplyr 0.6开始,它现在也可以理解列名。这使得使用select()进行编程更加容易:
> var
> select(flights,var,'day')
# A tibble: 336,776 x 3
year month day
1 2013 1 1
2 2013 1 1
3 2013 1 1
4 2013 1 1
5 2013 1 1
6 2013 1 1
7 2013 1 1
8 2013 1 1
9 2013 1 1
10 2013 1 1
# ... with 336,766 more rows
注意上面的代码有点不安全,因为你可能在tibble中添加了名为var的列,或者你可能将代码应用到了另一个包含这个列名的数据框上。为了避免这些问题,你可以将变量包裹在identity()函数中,就像我们上面提到的那样,因为这样会忽略列名。但是,一个更加直白和常用的方法是,所有的dplyr动词(verbs)中可以使用‘!!’操作符引用变量,它告诉dplyr忽略数据框,直接查看文本:
> #创建一个新的变量
> flights$vars
#如果你评估‘vars’时加上‘!!’操作符,这个新变量列就不会造成影响
> vars
> select(flights,!!vars)
# A tibble: 336,776 x 3
year month day
1 2013 1 1
2 2013 1 1
3 2013 1 1
4 2013 1 1
5 2013 1 1
6 2013 1 1
7 2013 1 1
8 2013 1 1
9 2013 1 1
10 2013 1 1
# ... with 336,766 more rows
在常规方程中使用dplyr时,这个方程非常有用,想学习更多可参考vignette(‘programming’)。但理解你所引用的动词的语义也是很重要的,也就是他们所理解的值。就像我们刚才提到的,select()支持列名和列的位置,但是在其他动词中情况并非如此,例如mutate(),因为他们语义不同。
变异(mutating)操作
Mutate的语义和selection的语义非常不同。Select()参数为列名或列位置,mutate()参数为列向量。我们将创建一个小的tibble来清晰了解一下这个不同:
> df
当我们用select()时,无修饰列名代表它们在tibble中的位置。而对于mutate()却是另一个含义,列标识代表存储在tibble中的整个列向量。想一下如果我们给mutate()一个字符串或一个数字会发生什么:
> mutate(df,'year',2)
# A tibble: 336,776 x 6
year month day dep_time `"year"` `2`
1 2013 1 1 517 year 2
2 2013 1 1 533 year 2
3 2013 1 1 542 year 2
4 2013 1 1 544 year 2
5 2013 1 1 554 year 2
6 2013 1 1 554 year 2
7 2013 1 1 555 year 2
8 2013 1 1 557 year 2
9 2013 1 1 557 year 2
10 2013 1 1 558 year 2
# ... with 336,766 more rows
Mutate()得到长度为1的向量,它将其解释为数据框中的新列,这些向量循环匹配行数。这就是为什么提供像‘year’+10这样的表达式是没有意义的,这个求和是给一个字符串‘year’加10!正确的表达式是(不带引号):
> mutate(df,year+10)
# A tibble: 336,776 x 5
year month day dep_time `year + 10`
1 2013 1 1 517 2023
2 2013 1 1 533 2023
3 2013 1 1 542 2023
4 2013 1 1 544 2023
5 2013 1 1 554 2023
6 2013 1 1 554 2023
7 2013 1 1 555 2023
8 2013 1 1 557 2023
9 2013 1 1 557 2023
10 2013 1 1 558 2023
# ... with 336,766 more rows
同样,如果这些值表示一个有效的列,则可以从上下文中引用值。它们必须长度为1(然后循环得到列)或者与数据框有相同的行数。下面我们将创建一个新向量,然后添加到数据框:
> var
> mutate(df,new=var)
# A tibble: 336,776 x 5
year month day dep_time new
1 2013 1 1 517 1
2 2013 1 1 533 2
3 2013 1 1 542 3
4 2013 1 1 544 4
5 2013 1 1 554 5
6 2013 1 1 554 6
7 2013 1 1 555 7
8 2013 1 1 557 8
9 2013 1 1 557 9
10 2013 1 1 558 10
# ... with 336,766 more rows
一个恰当的例子是group_by()。当你认为它选择了语义,它实际有包含mutate语义含义。这是十分方便的,因为这样允许用一个修改的列进行分组:
> group_by(df,month)
# A tibble: 336,776 x 4
# Groups: month [12]
year month day dep_time
1 2013 1 1 517
2 2013 1 1 533
3 2013 1 1 542
4 2013 1 1 544
5 2013 1 1 554
6 2013 1 1 554
7 2013 1 1 555
8 2013 1 1 557
9 2013 1 1 557
10 2013 1 1 558
# ... with 336,766 more rows
> group_by(df,month=as.factor(month))
# A tibble: 336,776 x 4
# Groups: month [12]
year month day dep_time
1 2013 1 1 517
2 2013 1 1 533
3 2013 1 1 542
4 2013 1 1 544
5 2013 1 1 554
6 2013 1 1 554
7 2013 1 1 555
8 2013 1 1 557
9 2013 1 1 557
10 2013 1 1 558
# ... with 336,766 more rows
这就是为什么不能提供一个列名给group_by(),这就相当于创建了一个新的列,其中包含的字符串循环的次数为整个行数。
> group_by(df,'month')
# A tibble: 336,776 x 5
# Groups: "month" [1]
year month day dep_time `"month"`
1 2013 1 1 517 month
2 2013 1 1 533 month
3 2013 1 1 542 month
4 2013 1 1 544 month
5 2013 1 1 554 month
6 2013 1 1 554 month
7 2013 1 1 555 month
8 2013 1 1 557 month
9 2013 1 1 557 month
10 2013 1 1 558 month
# ... with 336,766 more rows
因为有时候使用select语义也很有用,所以添加了group_by_at()变体。在dplyr中,变体后缀_at()在他们的第二个参数中支持select语义。你只需要用vars()包裹这个选择:
> group_by_at(df,vars(year:day))
# A tibble: 336,776 x 4
# Groups: year, month, day [365]
year month day dep_time
1 2013 1 1 517
2 2013 1 1 533
3 2013 1 1 542
4 2013 1 1 544
5 2013 1 1 554
6 2013 1 1 554
7 2013 1 1 555
8 2013 1 1 557
9 2013 1 1 557
10 2013 1 1 558
# ... with 336,766 more rows
你可以了解更多_at()和_if()变体在?Scoped帮助页面。
管道
就没有附带结果的函数调用而言,Dplyr的API是功能性的,你必须不停的保存它们的结果,这使得你无法写出特别优雅的代码,特别是想要一次性执行很多操作的时候,你却不得不一步一步执行:
> a1
> a2
Adding missing grouping variables: `year`, `month`, `day`
> a3
+ arr=mean(arr_delay,na.rm = TRUE),
+ dep=mean(dep_delay,na.rm = TRUE))
> a430|dep>30)
或者你不想命名这些中间结果并想一次完成,就需要在其他函数中包裹函数调用:
> filter(
+ summarise(
+ select(
+ group_by(flights,year,month,day),
+ arr_delay,dep_delay
+ ),
+ arr=mean(arr_delay,na.rm=TRUE),
+ dep=mean(dep_delay,na.rm = TRUE)
+ ),
+ arr>30|dep>30)
Adding missing grouping variables: `year`, `month`, `day`
# A tibble: 49 x 5
# Groups: year, month [11]
year month day arr dep
1 2013 1 16 34.24736 24.61287
2 2013 1 31 32.60285 28.65836
3 2013 2 11 36.29009 39.07360
4 2013 2 27 31.25249 37.76327
5 2013 3 8 85.86216 83.53692
6 2013 3 18 41.29189 30.11796
7 2013 4 10 38.41231 33.02368
8 2013 4 12 36.04814 34.83843
9 2013 4 18 36.02848 34.91536
10 2013 4 19 47.91170 46.12783
# ... with 39 more rows
这使得程序变得晦涩难懂,因为操作的顺序是由内向外的。因此,参数与函数之间有一段很长的距离。为了解决这个问题,dplyr提供了来自于magrittr的%>%操作,将x%>%f(x)转换为f(x,y),所以你可以使用它重写复杂的操作,然后i可以从左向右,从上到下读取:
> flights%>%
+ group_by(year,month,day)%>%
+ select(arr_delay,dep_delay)%>%
+ summarise(+ arr=mean(arr_delay,na.rm = TRUE),
+ dep=mean(dep_delay,na.rm = TRUE)+ )%>%
+ filter(arr>30|dep>30)
Adding missing grouping variables: `year`, `month`, `day`
# A tibble: 49 x 5
# Groups: year, month [11]
year month day arr dep
1 2013 1 16 34.24736 24.61287
2 2013 1 31 32.60285 28.65836
3 2013 2 11 36.29009 39.07360
4 2013 2 27 31.25249 37.76327
5 2013 3 8 85.86216 83.53692
6 2013 3 18 41.29189 30.11796
7 2013 4 10 38.41231 33.02368
8 2013 4 12 36.04814 34.83843
9 2013 4 18 36.02848 34.91536
10 2013 4 19 47.91170 46.12783
# ... with 39 more rows
其他数据源
和数据框一样,dplyr操作的数据可以可以用其它方式存储,像数据表(data tables)、数据库(databases)和多维矩阵(multidimensional arrays)等。
1)数据表
Dplyr还为所有的dplyr 中的verbs提供了data.table方法。如果你已经使用data.table,你可以使用dplyr语法进行数据操作以及data.table的其他任何事情。
对于多次操作,data.table可以变得更快,因为你通常可以同时使用多个verbs。例如,对data.table你可以在单步操作中同时使用mutate和select,它清楚知道对打算扔掉的行进行计算是很不明智的。
对data tables使用dplyr的好处:
(1)对于一般的数据操作工作,它将你从data.table的参考语义中隔离出来,并避免你意外修改数据。
(2)取代一个复杂的加下标操作符([)的方法,它提供了许多简单的方法。
2) 数据库(databases)
Dplyr同样允许你对一个远程数据库使用相同的verbs。 它负责为你生成SQL,这样你就不用频繁的切换语言。为了使用这些功能,你需要安装dplyr包,然后读取vignette(‘dplyr’)有关这些的详细情况。
3)多维矩阵/数据集(multidimensional array/cubes)
tbl_cube()为多维矩阵和多维数据集提供一个实验接口。如果你正在使用R中的数据形式,请联系我,这样我就可以更好地了解你的需求。
比较
与所有现有操作比较,dplyr:
1)将你的数据如何存储这个问题抽象化,所以你可以使用同一函数集对data frames、data tables、remote databases进行操作。这使得你只关注与你想获得什么,而不是关注后台的数据存储。
2)提供一个贴切的print()方法,不会向屏幕输出多页数据(这个灵感来自于data tables的输出)。
与基本函数(base functions)相比:
1)dplyr非常的一致,函数有相同的接口。所以一旦你精通一个,就可以很容易的学会其他函数。
2)基本函数是基于向量(vectors)的,而dplyr是基于数据框(data frames)的。
与plyr相比,dplyr:
1)更快
2)提供更好的外部集合连接思想
3)仅为数据框操作提供工具(例如多数dplyr等于ddply()+各种函数,do()等于dlply())
与事实上的数据框(data frame)方法相比:
1)它不会伪装你有一个数据框,如果你想运行lm等,你仍然需要手动下拉数据
2)它没有为R汇总函数(例如mean()或sum())提供方法
能力有限,翻译粗糙,仅供参考