magrittr – Ceci n’est pas un pipe. 2

没文化真可怕。之前写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.600   Min.   :2.5   Min.   :1.300   Min.   :0.200  
##  1st Qu.:4.975   1st Qu.:3.0   1st Qu.:1.400   1st Qu.:0.200  
##  Median :5.600   Median :3.2   Median :3.350   Median :1.100  
##  Mean   :5.638   Mean   :3.2   Mean   :3.388   Mean   :1.181  
##  3rd Qu.:6.350   3rd Qu.:3.4   3rd Qu.:5.200   3rd Qu.:2.075  
##  Max.   :6.800   Max.   :3.9   Max.   :5.900   Max.   :2.500  
##        Species 
##  setosa    :8  
##  versicolor:0  
##  virginica :8  
##                
##                
## 

创建函数

.还可以用来代表一个函数的输入

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

plot of chunk unnamed-chunk-3

## [1] -0.37414726 -0.02226741

%$%

对于有一些函数,它无法接受左边传过来的所有的数据,它只需要其中的一列,或者几列来进行计算。比如

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”)。

2 thoughts on “magrittr – Ceci n’est pas un pipe.

  1. Reply kaji331 8月 12,2015 4:27 上午

    国人做的pipeR我觉的也非常好用的,而且很简单,我自己用的话一般都用这个

Leave a Reply

  

  

  

%d 博主赞过: