#> [1] 0.4903279
#> [1] 500.9905
for loops with functionals.purrr::map() family of functions to apply a function to each element of a list or vector.purrr::reduce() to combine elements of a vector into a single result.purrr equivalents.A key feature of functional languages is their use of first-class functions.
In R, this means you can:
Many functional languages require functions to be pure.
runif(), read.csv(), and Sys.time() are not pure.print(), write.csv(), and <- are not pure.R is not a strictly functional language because it doesn’t require pure functions.
#> [1] 0.4903279
#> [1] 500.9905
Common examples:
lapply(), apply(), and tapply() in base Rpurrr::map()integrate() or optim()To become significantly more reliable, code must become more transparent. In particular, nested conditions and loops must be viewed with great suspicion. Complicated control flows confuse programmers. Messy code often hides bugs.
— Bjarne Stroustrup
for loops are too flexible. You’re iterating, but why?purrr::map() applies a function to each element of a vectormap(1:3, f) == list(f(1), f(2), f(3))
map_<type>() to return an atomic vectormap() returns a list.map_lgl() returns a logical vector.map_int() returns an integer vector.map_dbl() returns a double vector.map_chr() returns a character vector.map_<type>() to return an atomic vector (cont.)#> mpg cyl disp hp drat wt qsec vs
#> "double" "double" "double" "double" "double" "double" "double" "double"
#> am gear carb
#> "double" "double" "double"
#> mpg cyl disp hp drat wt qsec
#> 20.090625 6.187500 230.721875 146.687500 3.596563 3.217250 17.848750
#> vs am gear carb
#> 0.437500 0.406250 3.687500 2.812500
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> 25 3 27 22 22 29 30 2 2 3 6
purrr provides ~ shortcut:
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> 25 3 27 22 22 29 30 2 2 3 6
R 4.1.0 provides \() shortcut (\ == function):
map() with ... or via anonymous functionpurrr style: pipe simple steps together|> / %>%) + purrr ➡️ readable codepurrr::modify() returns the same type as the inputmap() always returns a list:
modify() returns the same type as the input:
purrr::map2() iterates over two vectors in parallelFind a weighted mean from 2 lists: observations (xs) & weights (ws).
map() passes the whole ws list to each call:
#> Error in `map_dbl()`:
#> ℹ In index: 1.
#> Caused by error in `weighted.mean.default()`:
#> ! 'x' and 'w' must have the same length
map2() iterates over xs and ws in parallel:
purrr::walk() is for functions called for their side effectscat(), write.csv(), ggsave().walk() returns its input invisibly.purrr::imap() iterates over values and indicesNamed input == map2(.x, names(.x), .f)
#> Sepal.Length
#> "The first value of 'Sepal.Length' is 5.1"
#> Sepal.Width
#> "The first value of 'Sepal.Width' is 3.5"
Unnamed input == map2(.x, seq_along(.x), .f)
purrr::pmap() iterates over multiple arguments in a listpmap() applies function to list of arguments
map2(x, y, f) is equivalent to pmap(list(x, y), f).pmap().purrr::reduce() combines vector elements with a binary functionreduce(1:4, f) is equivalent to f(f(f(1, 2), 3), 4).Example: Find the numbers that appear in every vector in a list.
purrr::accumulate() shows intermediate resultsreduce(), but returns all the intermediate results.reduce() works.purrr::accumulate() is useful for cumulative calculationsPredicate: function that returns single TRUE or FALSE.
some() / every() / none(): True for any / all / no elements?detect() / detect_index(): Find value / location of 1st match.keep() / discard(): Keep / drop all matching elements.map_if() and modify_if() transform elements where a predicate is trueE.g, calculate mean of only numeric columns in a data frame.
#> List of 3
#> $ num1: num 10
#> $ num2: num 6
#> $ chr1: chr [1:3] "a" "b" "c"
#> 'data.frame': 3 obs. of 3 variables:
#> $ num1: num 10 10 10
#> $ num2: num 6 6 6
#> $ chr1: chr "a" "b" "c"
base::apply() summarizes matrices and arraysapply(X, MARGIN, FUN): MARGIN? 1 for rows, 2 for columns.
#> [1] 8.5 9.5 10.5 11.5 12.5
#> [1] 3 8 13 18
Warning: apply() will coerce df to a matrix!
Base R includes several mathematical functionals.
integrate(): Find the area under a curve.uniroot(): Find where a function equals zero.optimise(): Find the minimum or maximum value of a function.