Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R piping (%>%) does not work with replicate function

Tags:

r

pipe

magrittr

I am trying to learn the piping function (%>%).
When trying to convert from this line of code to another line it does not work.

---- R code -- original version -----

set.seed(1014)
replicate(6,sample(1:8))
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1    3    7    4    5    1
[2,]    2    8    4    2    4    2
[3,]    5    4    8    5    8    5
[4,]    3    1    2    1    1    7
[5,]    4    6    3    7    7    3
[6,]    6    5    1    3    3    8
[7,]    8    7    5    8    6    6
[8,]    7    2    6    6    2    4

---- R code - recoded with the pipe ----

> sample(1:8) %>%  replicate(6,.)
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    7    7    7    7    7    7
[2,]    3    3    3    3    3    3
[3,]    2    2    2    2    2    2
[4,]    1    1    1    1    1    1
[5,]    5    5    5    5    5    5
[6,]    4    4    4    4    4    4
[7,]    8    8    8    8    8    8
[8,]    6    6    6    6    6    6

Notice that when using pipes, the sampling does not work giving me the same vector across.

like image 579
phage Avatar asked Apr 07 '17 16:04

phage


1 Answers

That's to be expected. replicate expects an expression, but when using the pipe operator as is you just paste the result of the call to sample() to replicate. So you get 6 times the same result.

You have to use quote() to pass the expression to replicate instead of the result, but you shouldn't forget to evaluate each of the repetitions of that expression.

quote(sample(c(1:10,-99),6,rep=TRUE)) %>% 
  replicate(6, .) %>%
  sapply(eval)

Gives:

    [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    5    2   10   10    9    2
[2,]    4    3    1    3  -99    1
[3,]   10    2    3    8    2    4
[4,]  -99    1    6    2   10    3
[5,]    8  -99    1    9    4    6
[6,]    4   10    8    1  -99    8

What happens here:

  • the piping sends and expression to replicate without evaluating it.
  • replicate replicates that expression and returns a list with 6 times that expression but without evaluating it.
  • sapply(eval) goes through the list and executes each expression in that list.

In your previous question (i.e. when using data.frame), you could have done eg:

quote(sample(c(1:10,-99),6,rep=TRUE)) %>% 
  replicate(6, .) %>%
  data.frame

Now the function data.frame would force the expressions to be executed, but you also end up with terrible variable names, i.e. the expression itself.

If you want to learn more about the issues here, you'll have to dive into what is called "lazy evaluation" and how that is dealt with exactly by the pipe operator. But in all honesty, I really don't see any advantage of using the pipe operator in this case. It's not even more readable.

As per Frank's comment: You can use a mixture of piping and nesting of functions to avoid the sapply. But for that, you have to contain the nested functions inside a code block or the pipe operator won't process it correctly:

quote(sample(c(1:10,-99),6,rep=TRUE)) %>% {
  replicate(6, eval(.)) }

Very interesting, but imho not really useful...

like image 193
Joris Meys Avatar answered Sep 22 '22 06:09

Joris Meys