*본 포스팅은 Win-Vector Blog의 글, magrittr’s Doppelgänger를 참고하여 작성하였습니다.

magrittr 패키지의 파이프(%>%) 연산자

dplyr 패키지(정확히는magrittr 패키지)에서는 파이프 연산자(%>%)를 제공합니다. R studio를 사용한다면 shift+ctrl+M 단축키로 쉽게 이용할 수 있습니다. 제 경우 파이프 연산자는 R 프로그래밍을 할 때 수많은 괄호로 쌓여진 소스를 컴퓨터가 아닌 인간의 입장에서 보기 편하게 만드는 Syntactic sugar의 역할을 해주기 때문에 편하게 사용하고 있습니다.모든 R에서 tidyverse를 로딩하게 만드려는 Hadley Wickham의 빅픽쳐.

예를 들어

sqrt(tan(cos(sin(7))))
## [1] 1.006459

요런 코드를

library("magrittr")
7 %>% sin() %>% cos() %>% tan() %>% sqrt()
## [1] 1.006459

요렇게 표현할 수 있습니다. 아마도 magrittr 패키지의 pipe는 Rene Magritte의 작품 <이미지의 배반>에 적힌 “Ceci n’est pas un pipe(이것은 파이프가 아니다)”를 패러디(?)한 것 같습니다.


<이미지의 배반, 르네 마그리트>

파이프 연산자에 대한 자세한 설명은 이미 많은분들이 작성해 놓았으니 아래부터는 magrittr 패키지 로딩 없이 pipe연산자를 사용하는 방법에 대한 이야기를 해보겠습니다. 바로 Bizzaro pipe (->.;)를 이용하는 것입니다(Bizzaro는 슈퍼맨의 복제 빌런 이름입니다).

Bizzaro pipe (->.;)

7 ->.; sin(.) ->.; cos(.) ->.; tan(.) ->.; sqrt(.)
## [1] 1.006459

간단하게 이야기 하자면 7. 으로 정의한 이후(;), sin 함수 안에 .을 넣는 과정이라고 생각하면 될 것 같습니다. 사실 .을 사용하지 않고 아래와 같이 해도 문제 없습니다.

7 ->a; sin(a) ->a; cos(a) ->a; tan(a) ->a; sqrt(a)
## [1] 1.006459

Bizzaro pipe를 이용한 속도개선

굳이 Bizzaro pipe의 장점을 이야기 하자면 아주미미한속도개선이라 할 수 있겠습니다. 먼저 함수를 상황에 따라 네가지로 정의하고 비교해 보겠습니다.

fbasic <- function(d) {
  sqrt(tan(cos(sin(d))))
}

fmagrittr <- function(d) {
  (d %>% sin() %>% cos() %>% tan() %>% sqrt())
}

fmagrittrdot <- function(d) {
  d %>% sin(.) %>% cos(.) %>% tan(.) %>% sqrt(.)
}

fsemicolon <- function(d) {
  d ->.; sin(.) ->.; cos(.) ->.; tan(.) ->.; sqrt(.)
}

앞서 system.time() 함수를 사용해 속도를 비교해 봤지만 모든 결과가 0으로 나왔습니다. 더 작은 단위를 비교하기 위해 microbenchmark 패키지를 이용해 보겠습니다.

library(microbenchmark)
set.seed(160415) #Birthday of my son :)
bm <- microbenchmark(
  fbasic(7),
  fmagrittr(7),
  fmagrittrdot(7),
  fsemicolon(7),
  control=list(warmup=100L,
               order='random'),
  times=10000L
)

print(bm)
## Unit: nanoseconds
##             expr    min     lq       mean median     uq      max neval cld
##        fbasic(7)      0    321   1598.471    641    962  4615465 10000 a
##     fmagrittr(7) 146578 162295 222494.085 171276 200463 51596344 10000   c
##  fmagrittrdot(7) 135673 149144 199278.335 157484 184747 16283707 10000  b
##    fsemicolon(7)      0    641   1764.496    642    962  3268673 10000 a

산술평균적으로 보았을 때 기존 파이프 연산자에 비해 Bizzaro 파이프가 181,058 나노초(0.000181058초) 빠릅니다. 시각화를 시키면 다음과 같습니다.

library(ggplot2)
highcut <- quantile(bm$time,probs=0.95)
ggplot(data=as.data.frame(bm),aes(x=time,color=expr)) +
  geom_density(adjust=0.3) +
  facet_wrap(~expr,ncol=1,scales = 'free_y') +
  scale_x_continuous(limits = c(min(bm$time),highcut))