没文化真可怕。之前写R中的pipelining(chaining)概念的时候,我就一直在想,为什么pipe的包要叫一个magrittr?然后就在网上查呀查,发现怎么没人解释一下。
后来查magritte的时候空然发现一幅图,这幅图在很多人介绍magrittr包的时候都用到了。我再一查,明白了。原来,这个叫Ren’{e} Magritte比利时超现实主义画家在30岁的时候画过一幅画,叫“The Treachery of Images”,图中画了一个烟斗,下面配字,写到,“Ceci n’est pas une pipe”(翻译过来就是说:这不是一个烟斗)。就是这幅画了。
而magrittr的作者Stefan Milton Bache就是借用了这句Ceci n’est pas une pipe来解释它的magrittr的。有文化的人一下子就可以联想到pipe。嗯,我自省一会儿先。
之前讲的magrittr包只介绍了它的一部分,而且并不是非常清楚。今天把它的说明文档贴上来。
关键字有:%>%, %T>%, %$%, %<>%。
%>%
简单地讲,pipe就是从左向右顺序操作。
- x %>% f 等于 f(x)
- x %>% f(y) 等于 f(x, y)
- x %>% f %>% g %>% h 等于 h(g(f(x)))
. (参数容器)
- x %>% f(y, .) 等于 f(y, x)
- x %>% f(y, z = .) 等于 f(y, z = x)
参数容器重用
很多情况下我们需要对相同的数据做不同的操作,这个时候就可以使用到重用(re-use)的概念。
- x %>% f(y = nrow(.), z = ncol(.)) 等于 f(x, y = nrow(x), z = ncol(x))
- x %>% {f(y = nrow(.), z = ncol(.))} 等于 f(y = nrow(x), z = ncol(x)) ## 注意这里的大括号,以及参数的变化
更复杂的情况
之前我讲过,.(点符号)其实相当于shell pipe中的“-”(小短杠)或者stdin。
library(magrittr)
iris %>%
{
n <- sample(1:10, size = 1)
H <- head(., n)
T <- tail(., n)
rbind(H, T)
} %>%
summary
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## Min. :4.900 Min. :3.000 Min. :1.400 Min. :0.200
## 1st Qu.:5.050 1st Qu.:3.000 1st Qu.:1.400 1st Qu.:0.200
## Median :5.500 Median :3.200 Median :3.250 Median :1.000
## Mean :5.525 Mean :3.225 Mean :3.325 Mean :1.125
## 3rd Qu.:5.975 3rd Qu.:3.425 3rd Qu.:5.175 3rd Qu.:1.925
## Max. :6.200 Max. :3.500 Max. :5.400 Max. :2.300
## Species
## setosa :2
## versicolor:0
## virginica :2
##
##
##
创建函数
.还可以用来代表一个函数的输入
f <- . %>% cos %>% sin
f(1)
## [1] 0.5143953
## 相当于
f <- function(.) sin(cos(.))
f(1)
## [1] 0.5143953
%T>%
%>%的确非常简单,但是有些时候,我们需要查看一点中间结果,这个时候就不得不打断pipe了。有了T操作符(%T>%),就可以写成一行了。
rnorm(200) %>%
matrix(ncol = 2) %T>%
plot %>% # plot的结果我们不需要,%T>%帮助我们把左边的结果传给plot后保留下来再传给colSums。
colSums
## [1] 23.747943 3.263112
%$%
对于有一些函数,它无法接受左边传过来的所有的数据,它只需要其中的一列,或者几列来进行计算。比如
iris %>%
subset(Sepal.Length > mean(Sepal.Length)) %$%
cor(Sepal.Length, Sepal.Width)
## [1] 0.3361992
有些同学会说,那我也可以这样啊
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
iris %>%
subset(Sepal.Length > mean(Sepal.Length)) %>%
select(Sepal.Length, Sepal.Width) %>%
cor
## Sepal.Length Sepal.Width
## Sepal.Length 1.0000000 0.3361992
## Sepal.Width 0.3361992 1.0000000
好吧,我来举一个比较严格的例子
iris %>%
subset(Sepal.Length > mean(Sepal.Length)) %$%
add(Sepal.Length, Sepal.Width) %>%
head
## [1] 10.2 9.6 10.0 9.3 9.6 9.5
%<>%
有时候我们会对变量操作后赋值回去,比如
a <- b <- iris$Sepal.Length
a <-
a %>%
sqrt
如果用%<>%的话,就可以把上面的操作简化成
b %<>% sqrt
identical(a, b) ## 结果一致
## [1] TRUE
了解更多,请使用vignette(“magrittr”)。
国人做的pipeR我觉的也非常好用的,而且很简单,我自己用的话一般都用这个
谢谢分享。我研究一下pipeR,以前对pipe都提不起学习的兴趣,现在不学不行了。