Combining pipes and the magrittr dot (.) placeholder
The "problem" is that magrittr has a short-hand notation for anonymous functions:
. %>% is.data.frame
is roughly the same as
function(.) is.data.frame(.)
In other words, when the dot is the (left-most) left-hand side, the pipe has special behaviour.
You can escape the behaviour in a few ways, e.g.
(.) %>% is.data.frame
or any other way where the LHS is not identical to .
In this particular example, this may seem as undesirable behaviuour, but commonly in examples like this there's really no need to pipe the first expression, so is.data.frame(.)
is as expressive as . %>% is.data.frame
, and
examples like
data %>%
some_action %>%
lapply(. %>% some_other_action %>% final_action)
can be argued to be clearner than
data %>%
some_action %>%
lapply(function(.) final_action(some_other_action(.)))
dot notation in magrittr pipe not be
.
in this case refers to data which is present in the previous step which is (data %>% group_by(carb)
). Although the data is grouped it is still complete data. If you are on dplyr
> 1.0.0 you could use cur_data()
to refer to the data in the group.
library(dplyr)
library(broom)
library(tidyr)
data %>%
group_by(carb) %>%
summarize(new = list(tidy(lm(formula = drat ~ mpg, data = cur_data())))) %>%
unnest(cols = new)
This gives the same output as your first example.
R combinations with dot (.), ~, and pipe (%%) operator
That line uses the .
in three different ways.
[1] [2] [3]
aggregate(. ~ cyl, data = ., FUN = . %>% mean %>% round(2))
Generally speaking you pass in the value from the pipe into your function at a specific location with .
but there are some exceptions. One exception is when the .
is in a formula. The ~
is used to create formulas in R. The pipe wont change the meaning of the formula, so it behaves like it would without any escaping. For example
aggregate(. ~ cyl, data=mydata)
And that's just because aggregate
requires a formula with both a left and right hand side. So the .
at [1]
just means "all the other columns in the dataset." This use is not at all related to magrittr.
The .
at [2]
is the value that's being passed in as the pipe. If you have a plain .
as a parameter to the function, that's there the value will be placed. So the result of the subset()
will go to the data=
parameter.
The magrittr
library also allows you to define anonymous functions with the .
variable. If you have a chain that starts with a .
, it's treated like a function. so
. %>% mean %>% round(2)
is the same as
function(x) round(mean(x), 2)
so you're just creating a custom function with the .
at [3]
Native pipe placeholder
The native R pipe does not use dot. It always inserts into the first argument. To get the effect of dot define a function or if it is at the beginning combine it yourself repeating the input (or break it up into two pipelines and do the same -- not shown since doesn't apply here).
library(dplyr)
mtcars |>
(\(x) filter(x, complete.cases(x)))() |>
summary()
or
f <- function(x) filter(x, complete.cases(x))
mtcars |> f() |> summary()
or
filter(mtcars, complete.cases(mtcars)) |> summary()
Sometimes with
can be used to create a workaround. This creates a list with one element named x and then uses that in the next leg of the pipe.
mtcars |>
list() |>
setNames("x") |>
with(filter(x, complete.cases(x))) |>
summary()
Note that you can do this with only base R -- the Bizarro pipe which is not really a pipe but looks like one.
mtcars ->.;
filter(., complete.cases(.)) ->.;
summary(.)
Update
Since this question appeared R has added a _ placeholder so the with
example could be shortened to:
# needs R 4.2 or later
mtcars |>
list(x = _) |>
with(filter(x, complete.cases(x))) |>
summary()
`magrittr` pipe into apply
Here are two ways, with the magrittr
and native pipes.
suppressPackageStartupMessages(library(magrittr))
dat <- 1:10
locs <- list(c(1, 2),
c(3, 4),
c(5, 6))
foo <- function(x, y, z) {
out <- mean(c(x[y], x[z]))
return(out)
}
# wrap the function around parenthesis
dat %>%
(\(d) lapply(locs, \(z) foo(., z[1], z[2])))()
#> [[1]]
#> [1] 1.5
#>
#> [[2]]
#> [1] 3.5
#>
#> [[3]]
#> [1] 5.5
# New native pipe with anonymous function
dat |>
{\(d) lapply(locs, \(z) foo(x = d, z[1], z[2]))}()
#> [[1]]
#> [1] 1.5
#>
#> [[2]]
#> [1] 3.5
#>
#> [[3]]
#> [1] 5.5
Created on 2022-05-18 by the reprex package (v2.0.1)
How to combine magrittr pipes and %in% inside a dplyr::filter predicate function?
Don't make this complicated for its own sake.
ids <- (df %>% count(id) %>% arrange(n) %>% tail(2))$id
filter(df, id %in% ids)
Related Topics
R - Error When Using Geturl from Curl After Site Was Changed
Run R Interactively from Rscript
How to Create a Continuous Legend (Color Bar Style) for Scale_Alpha
Creating a Cumulative Step Graph in R
Single Legend When Using Group, Linetype and Colour in Ggplot2
What's The Difference Between [1], [1,], [,1], [[1]] for a Dataframe in R
Why Does Apt-Get Install R-Base Install 3.2.3 Instead of 3.4.0 in R
How to Show Only The Lower Triangle in Ggpairs
How to Subset a Table Object in R
Extract Only Folder Name Right Before Filename from Full Path
In R, Merge Two Data Frames, Fill Down The Blanks
Ggplot and Axis Numbers and Labels
Trouble Getting Latest Version of Gdal on Ubuntu Running R
How to Split a Dataframe Column by The First Instance of a Character in Its Values
Get Plot() Bounding Box Values
Ggplot2: How to Separate Geom_Polygon and Geom_Line in Legend Keys