Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using the %>% pipe, and dot (.) notation

Tags:

r

magrittr

When using map on a nested data_frame, I do not understand why the latter two version give an error, how should I use the dot (.)?

library(tidyverse)
# dummy data
df <- tibble(id = rep(1:10, each = 10), 
                 val = runif(100))
df <- nest(df, -id)

# works as expected
map(df$data, min)
df %>% .$data %>% map(., min)

# gives an error
df %>% map(.$data, min)
# Error: Don't know how to index with object of type list at level 1

df %>% map(data, min)
like image 395
johannes Avatar asked Feb 22 '17 07:02

johannes


People also ask

What is %>% in coding?

%>% is called the forward pipe operator in R. It provides a mechanism for chaining commands with a new forward-pipe operator, %>%. This operator will forward a value, or the result of an expression, into the next function call/expression.

What does the pipe operator %>% do?

What does the pipe do? The pipe operator, written as %>% , has been a longstanding feature of the magrittr package for R. It takes the output of one function and passes it into another function as an argument. This allows us to link a sequence of analysis steps.

What is the dot in Tidyverse?

The dot is used within dplyr mainly (not exclusively) in mutate_each , summarise_each and do . In the first two (and their SE counterparts) it refers to all the columns to which the functions in funs are applied. In do it refers to the (potentially grouped) data. frame so you can reference single columns by using .


1 Answers

The problem isn't map, but rather how the %>% pipe deals with the .. Consider the following examples (remember that / is a two argument function in R):

Simple piping:

1 %>% `/`(2) 

Is equivalent to `/`(1, 2) or 1 / 2 and gives 0.5.

It is also equivalent to 1 %>% `/`(., 2).

Simple . use:

1 %>% `/`(2, .) 

Is equivalent to `/`(2, 1) or 2 / 1 and gives 2.

You can see that 1 is no longer used as the first argument, but only as the second.

Other . use:

This doesn't work however, when subsetting the .:

list(a = 1) %>% `/`(.$a, 2) 
Error in `/`(., .$a, 2) : operator needs one or two arguments 

We can see that . got injected twice, as the first argument and subsetted in the second argument. An expression like .$a is sometimes referred to as a nested function call (the $ function is used inside the / function, in this case).

We use braces to avoid first argument injection:

list(a = 1) %>% { `/`(.$a, 2) } 

Gives 0.5 again.

Actual problem:

You are actually calling map(df, df$data, min), not map(df$data, min).

Solution:

Use braces:

df %>% { map(.$data, min) } 

Also see the header Using the dot for secondary purposes in ?magrittr::`%>%` which reads:

In particular, if the placeholder is only used in a nested function call, lhs will also be placed as the first argument! The reason for this is that in most use-cases this produces the most readable code. For example, iris %>% subset(1:nrow(.) %% 2 == 0) is equivalent to iris %>% subset(., 1:nrow(.) %% 2 == 0) but slightly more compact. It is possible to overrule this behavior by enclosing the rhs in braces. For example, 1:10 %>% {c(min(.), max(.))} is equivalent to c(min(1:10), max(1:10)).

like image 96
Axeman Avatar answered Sep 19 '22 06:09

Axeman