An introduction to functional programming
R Day Colombia
Co-organizer R-Ladies São Paulo
PhD Candidate in Environmental Sciences at the University of Sao Paulo, Brazil
Teacher and Consultant at Curso-R
Tidyverse certified instructor - Posit
Contact:
Inspired by the Spanish version: https://es.r4ds.hadley.nz/
Functional programming is a programming paradigm
Functions are really important in this context!
A function is a set of instructions that takes an input (arguments) and returns an output.
You can encapsulate and reuse code.
Instead of writing this command in the terminal:
You can use this function in R:
A function has:
a name
arguments
a body
a return value (it is the last line of the function)
In Brazil, we use the date format dd/mm/yyyy
: 21/01/2021.
We can use the function as.Date()
to convert the date format, but we need to specify the format of the date.
A toolbox for functional programming
Many of the functions in purrr are alternatives to for
loops
Code with purrr is shorter and clearer than for
loops
Knowing how to use purrr allows you to use the furrr package: it has the same syntax, but allows you to run code in parallel
Source: Hadley Wickham
purrr has many functions!
Many work similarly.
We will focus on some today :)
Examples on daily tasks!
purrr::map()
purrr::map()
is the most important function in purrr
Given an object (can be a vector or a list) we want to apply a function to each element of that object.
It returns a list
map_*()
and have similar behaviorpurrr::map()
purrr::map_vec()
!map_vec()
is a variant of map()
that always returns a vector!
It is useful when you want to apply a function to each element of a vector and return a vector.
purrr::list_c()
!list_c()
is a function that takes a list and returns a vector
It is useful to use after map()
, and you want to convert the list into a vector
purrr::pluck()
pluck()
is a function that extracts a single element from a list
pluck()
can be used to extract elements from nested lists. That’s where it shines!
We will use a simple list for the examples:
purrr::pluck()
[[ ]]
instead?pluck()
:[[ ]]
:|>
pluck()
:[[ ]]
:If the element does not exist, it returns NULL
instead of an error.
With pluck()
:
[[ ]]
:list_rbind()
, list_cbind()
list_rbind()
and list_cbind()
are functions that bind lists that contains dataframes (by row or column) and returns a tibble.
Let’s see a real life example!
“I have a folder with multiple files that I want to import. How can I do that?”
Remember: to use map()
, we need:
a vector or a list of the elements that we want to apply the function;
a function.
If we want to import one file, we can use readxl::read_excel()
:
library(readxl)
recent_chla <- read_excel("data/ex-1/RelatorioQualidadeAguasSuperficiais_clorofila-a_2018-2022.xlsx")
glimpse(recent_chla)
Rows: 63
Columns: 26
$ `Período DE` <chr> "01/01/2018", "01/01/2018", "01/01/2018", "0…
$ `Período ATE` <chr> "16/10/2022", "16/10/2022", "16/10/2022", "1…
$ Cod_Interaguas <chr> "1386", "1386", "1386", "1386", "1386", "138…
$ `Tipo Rede` <chr> "Rede Básica", "Rede Básica", "Rede Básica",…
$ UGRHI <chr> "06 - ALTO TIÊTE", "06 - ALTO TIÊTE", "06 - …
$ `Código Ponto` <chr> "BILL02030", "BILL02030", "BILL02030", "BILL…
$ `Status Ponto` <chr> "Ativo", "Ativo", "Ativo", "Ativo", "Ativo",…
$ `Data Coleta` <chr> "11/01/2018", "22/05/2018", "26/07/2018", "2…
$ `Hora Coleta` <chr> "13:44", "13:33", "16:29", "14:12", "10:00",…
$ Parametro <chr> "Clorofila-a", "Clorofila-a", "Clorofila-a",…
$ Sinal <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ Valor <chr> "368,87000000", "47,22000000", "53,46000000"…
$ Unidade <chr> "µg/L", "µg/L", "µg/L", "µg/L", "µg/L", "µg/…
$ `Tipo Parâmetro` <chr> "5- Hidrobiológicos", "5- Hidrobiológicos", …
$ `Sistema Hídrico` <chr> "Reservatório Billings - BILL", "Reservatóri…
$ `Tipo de Sistema Hídrico` <chr> "Reservatório (Lêntico)", "Reservatório (Lên…
$ CLASSE <chr> "Classe 2", "Classe 2", "Classe 2", "Classe …
$ Município <chr> "SÃO PAULO", "SÃO PAULO", "SÃO PAULO", "SÃO …
$ UF <chr> "SP", "SP", "SP", "SP", "SP", "SP", "SP", "S…
$ `Inicio Operação` <chr> "01/01/2007", "01/01/2007", "01/01/2007", "0…
$ `Fim Operação` <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ Latitude <chr> "23 43 04", "23 43 04", "23 43 04", "23 43 0…
$ Longitude <chr> "46 39 51", "46 39 51", "46 39 51", "46 39 5…
$ Altitude <chr> "743", "743", "743", "743", "743", "743", "7…
$ Localização <chr> "No meio do corpo central, cerca de 1,5 km d…
$ Captação <chr> "N", "N", "N", "N", "N", "N", "N", "N", "N",…
But we want to import multiple files!
The function is the same (readxl::read_excel()
), but we need to apply it to multiple files.
We need to create a vector with all the file paths!
files_to_import <-
list.files(path = "data/ex-1",
pattern = "*.xlsx",
full.names = TRUE)
files_to_import
[1] "data/ex-1/RelatorioQualidadeAguasSuperficiais_clorofila-a_2008-2012.xlsx"
[2] "data/ex-1/RelatorioQualidadeAguasSuperficiais_clorofila-a_2013-2017.xlsx"
[3] "data/ex-1/RelatorioQualidadeAguasSuperficiais_clorofila-a_2018-2022.xlsx"
[4] "data/ex-1/RelatorioQualidadeAguasSuperficiais_PT_2008-2012.xlsx"
[5] "data/ex-1/RelatorioQualidadeAguasSuperficiais_PT_2013-2017.xlsx"
[6] "data/ex-1/RelatorioQualidadeAguasSuperficiais_PT_2018-2022.xlsx"
readxl::read_excel()
:[[1]]
# A tibble: 102 × 26
`Período DE` `Período ATE` Cod_Interaguas `Tipo Rede` UGRHI `Código Ponto`
<chr> <chr> <chr> <chr> <chr> <chr>
1 01/01/2008 31/12/2012 1386 Rede Básica 06 - AL… BILL02030
2 01/01/2008 31/12/2012 1386 Rede Básica 06 - AL… BILL02030
3 01/01/2008 31/12/2012 1386 Rede Básica 06 - AL… BILL02030
4 01/01/2008 31/12/2012 1386 Rede Básica 06 - AL… BILL02030
5 01/01/2008 31/12/2012 1386 Rede Básica 06 - AL… BILL02030
6 01/01/2008 31/12/2012 1386 Rede Básica 06 - AL… BILL02030
7 01/01/2008 31/12/2012 1386 Rede Básica 06 - AL… BILL02030
8 01/01/2008 31/12/2012 1386 Rede Básica 06 - AL… BILL02030
9 01/01/2008 31/12/2012 1386 Rede Básica 06 - AL… BILL02030
10 01/01/2008 31/12/2012 1386 Rede Básica 06 - AL… BILL02030
# ℹ 92 more rows
# ℹ 20 more variables: `Status Ponto` <chr>, `Data Coleta` <chr>,
# `Hora Coleta` <chr>, Parametro <chr>, Sinal <lgl>, Valor <chr>,
# Unidade <chr>, `Tipo Parâmetro` <chr>, `Sistema Hídrico` <chr>,
# `Tipo de Sistema Hídrico` <chr>, CLASSE <chr>, Município <chr>, UF <chr>,
# `Inicio Operação` <chr>, `Fim Operação` <lgl>, Latitude <chr>,
# Longitude <chr>, Altitude <chr>, Localização <chr>, Captação <chr>
[[2]]
# A tibble: 160 × 26
`Período DE` `Período ATE` Cod_Interaguas `Tipo Rede` UGRHI `Código Ponto`
<chr> <chr> <chr> <chr> <chr> <chr>
1 01/01/2013 31/12/2017 1386 Rede Básica 06 - AL… BILL02030
2 01/01/2013 31/12/2017 1386 Rede Básica 06 - AL… BILL02030
3 01/01/2013 31/12/2017 1386 Rede Básica 06 - AL… BILL02030
4 01/01/2013 31/12/2017 1386 Rede Básica 06 - AL… BILL02030
5 01/01/2013 31/12/2017 1386 Rede Básica 06 - AL… BILL02030
6 01/01/2013 31/12/2017 1386 Rede Básica 06 - AL… BILL02030
7 01/01/2013 31/12/2017 1386 Rede Básica 06 - AL… BILL02030
8 01/01/2013 31/12/2017 1386 Rede Básica 06 - AL… BILL02030
9 01/01/2013 31/12/2017 1386 Rede Básica 06 - AL… BILL02030
10 01/01/2013 31/12/2017 1386 Rede Básica 06 - AL… BILL02030
# ℹ 150 more rows
# ℹ 20 more variables: `Status Ponto` <chr>, `Data Coleta` <chr>,
# `Hora Coleta` <chr>, Parametro <chr>, Sinal <lgl>, Valor <chr>,
# Unidade <chr>, `Tipo Parâmetro` <chr>, `Sistema Hídrico` <chr>,
# `Tipo de Sistema Hídrico` <chr>, CLASSE <chr>, Município <chr>, UF <chr>,
# `Inicio Operação` <chr>, `Fim Operação` <lgl>, Latitude <chr>,
# Longitude <chr>, Altitude <chr>, Localização <chr>, Captação <chr>
[[3]]
# A tibble: 63 × 26
`Período DE` `Período ATE` Cod_Interaguas `Tipo Rede` UGRHI `Código Ponto`
<chr> <chr> <chr> <chr> <chr> <chr>
1 01/01/2018 16/10/2022 1386 Rede Básica 06 - AL… BILL02030
2 01/01/2018 16/10/2022 1386 Rede Básica 06 - AL… BILL02030
3 01/01/2018 16/10/2022 1386 Rede Básica 06 - AL… BILL02030
4 01/01/2018 16/10/2022 1386 Rede Básica 06 - AL… BILL02030
5 01/01/2018 16/10/2022 1386 Rede Básica 06 - AL… BILL02030
6 01/01/2018 16/10/2022 1386 Rede Básica 06 - AL… BILL02030
7 01/01/2018 16/10/2022 1386 Rede Básica 06 - AL… BILL02030
8 01/01/2018 16/10/2022 1386 Rede Básica 06 - AL… BILL02030
9 01/01/2018 16/10/2022 1386 Rede Básica 06 - AL… BILL02030
10 01/01/2018 16/10/2022 1386 Rede Básica 06 - AL… BILL02030
# ℹ 53 more rows
# ℹ 20 more variables: `Status Ponto` <chr>, `Data Coleta` <chr>,
# `Hora Coleta` <chr>, Parametro <chr>, Sinal <lgl>, Valor <chr>,
# Unidade <chr>, `Tipo Parâmetro` <chr>, `Sistema Hídrico` <chr>,
# `Tipo de Sistema Hídrico` <chr>, CLASSE <chr>, Município <chr>, UF <chr>,
# `Inicio Operação` <chr>, `Fim Operação` <lgl>, Latitude <chr>,
# Longitude <chr>, Altitude <chr>, Localização <chr>, Captação <chr>
[[4]]
# A tibble: 120 × 26
`Período DE` `Período ATE` Cod_Interaguas `Tipo Rede` UGRHI `Código Ponto`
<chr> <chr> <chr> <chr> <chr> <chr>
1 01/01/2008 31/12/2012 1386 Rede Básica 06 - AL… BILL02030
2 01/01/2008 31/12/2012 1386 Rede Básica 06 - AL… BILL02030
3 01/01/2008 31/12/2012 1386 Rede Básica 06 - AL… BILL02030
4 01/01/2008 31/12/2012 1386 Rede Básica 06 - AL… BILL02030
5 01/01/2008 31/12/2012 1386 Rede Básica 06 - AL… BILL02030
6 01/01/2008 31/12/2012 1386 Rede Básica 06 - AL… BILL02030
7 01/01/2008 31/12/2012 1386 Rede Básica 06 - AL… BILL02030
8 01/01/2008 31/12/2012 1386 Rede Básica 06 - AL… BILL02030
9 01/01/2008 31/12/2012 1386 Rede Básica 06 - AL… BILL02030
10 01/01/2008 31/12/2012 1386 Rede Básica 06 - AL… BILL02030
# ℹ 110 more rows
# ℹ 20 more variables: `Status Ponto` <chr>, `Data Coleta` <chr>,
# `Hora Coleta` <chr>, Parametro <chr>, Sinal <chr>, Valor <chr>,
# Unidade <chr>, `Tipo Parâmetro` <chr>, `Sistema Hídrico` <chr>,
# `Tipo de Sistema Hídrico` <chr>, CLASSE <chr>, Município <chr>, UF <chr>,
# `Inicio Operação` <chr>, `Fim Operação` <lgl>, Latitude <chr>,
# Longitude <chr>, Altitude <chr>, Localização <chr>, Captação <chr>
[[5]]
# A tibble: 141 × 26
`Período DE` `Período ATE` Cod_Interaguas `Tipo Rede` UGRHI `Código Ponto`
<chr> <chr> <chr> <chr> <chr> <chr>
1 01/01/2013 31/01/2017 1386 Rede Básica 06 - AL… BILL02030
2 01/01/2013 31/01/2017 1386 Rede Básica 06 - AL… BILL02030
3 01/01/2013 31/01/2017 1386 Rede Básica 06 - AL… BILL02030
4 01/01/2013 31/01/2017 1386 Rede Básica 06 - AL… BILL02030
5 01/01/2013 31/01/2017 1386 Rede Básica 06 - AL… BILL02030
6 01/01/2013 31/01/2017 1386 Rede Básica 06 - AL… BILL02030
7 01/01/2013 31/01/2017 1386 Rede Básica 06 - AL… BILL02030
8 01/01/2013 31/01/2017 1386 Rede Básica 06 - AL… BILL02030
9 01/01/2013 31/01/2017 1386 Rede Básica 06 - AL… BILL02030
10 01/01/2013 31/01/2017 1386 Rede Básica 06 - AL… BILL02030
# ℹ 131 more rows
# ℹ 20 more variables: `Status Ponto` <chr>, `Data Coleta` <chr>,
# `Hora Coleta` <chr>, Parametro <chr>, Sinal <chr>, Valor <chr>,
# Unidade <chr>, `Tipo Parâmetro` <chr>, `Sistema Hídrico` <chr>,
# `Tipo de Sistema Hídrico` <chr>, CLASSE <chr>, Município <chr>, UF <chr>,
# `Inicio Operação` <chr>, `Fim Operação` <lgl>, Latitude <chr>,
# Longitude <chr>, Altitude <chr>, Localização <chr>, Captação <chr>
[[6]]
# A tibble: 78 × 26
`Período DE` `Período ATE` Cod_Interaguas `Tipo Rede` UGRHI `Código Ponto`
<chr> <chr> <chr> <chr> <chr> <chr>
1 01/01/2018 16/10/2022 1386 Rede Básica 06 - AL… BILL02030
2 01/01/2018 16/10/2022 1386 Rede Básica 06 - AL… BILL02030
3 01/01/2018 16/10/2022 1386 Rede Básica 06 - AL… BILL02030
4 01/01/2018 16/10/2022 1386 Rede Básica 06 - AL… BILL02030
5 01/01/2018 16/10/2022 1386 Rede Básica 06 - AL… BILL02030
6 01/01/2018 16/10/2022 1386 Rede Básica 06 - AL… BILL02030
7 01/01/2018 16/10/2022 1386 Rede Básica 06 - AL… BILL02030
8 01/01/2018 16/10/2022 1386 Rede Básica 06 - AL… BILL02030
9 01/01/2018 16/10/2022 1386 Rede Básica 06 - AL… BILL02030
10 01/01/2018 16/10/2022 1386 Rede Básica 06 - AL… BILL02030
# ℹ 68 more rows
# ℹ 20 more variables: `Status Ponto` <chr>, `Data Coleta` <chr>,
# `Hora Coleta` <chr>, Parametro <chr>, Sinal <chr>, Valor <chr>,
# Unidade <chr>, `Tipo Parâmetro` <chr>, `Sistema Hídrico` <chr>,
# `Tipo de Sistema Hídrico` <chr>, CLASSE <chr>, Município <chr>, UF <chr>,
# `Inicio Operação` <chr>, `Fim Operação` <lgl>, Latitude <chr>,
# Longitude <chr>, Altitude <chr>, Localização <chr>, Captação <chr>
map()
returns a list!list_rbind()
:Rows: 664
Columns: 26
$ `Período DE` <chr> "01/01/2008", "01/01/2008", "01/01/2008", "0…
$ `Período ATE` <chr> "31/12/2012", "31/12/2012", "31/12/2012", "3…
$ Cod_Interaguas <chr> "1386", "1386", "1386", "1386", "1386", "138…
$ `Tipo Rede` <chr> "Rede Básica", "Rede Básica", "Rede Básica",…
$ UGRHI <chr> "06 - ALTO TIÊTE", "06 - ALTO TIÊTE", "06 - …
$ `Código Ponto` <chr> "BILL02030", "BILL02030", "BILL02030", "BILL…
$ `Status Ponto` <chr> "Ativo", "Ativo", "Ativo", "Ativo", "Ativo",…
$ `Data Coleta` <chr> "22/01/2008", "26/03/2008", "14/05/2008", "1…
$ `Hora Coleta` <chr> "11:20", "11:22", "12:30", "11:50", "11:20",…
$ Parametro <chr> "Clorofila-a", "Clorofila-a", "Clorofila-a",…
$ Sinal <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ Valor <chr> "18,71000000", "28,87000000", "31,19000000",…
$ Unidade <chr> "µg/L", "µg/L", "µg/L", "µg/L", "µg/L", "µg/…
$ `Tipo Parâmetro` <chr> "5- Hidrobiológicos", "5- Hidrobiológicos", …
$ `Sistema Hídrico` <chr> "Reservatório Billings - BILL", "Reservatóri…
$ `Tipo de Sistema Hídrico` <chr> "Reservatório (Lêntico)", "Reservatório (Lên…
$ CLASSE <chr> "Classe 2", "Classe 2", "Classe 2", "Classe …
$ Município <chr> "SÃO PAULO", "SÃO PAULO", "SÃO PAULO", "SÃO …
$ UF <chr> "SP", "SP", "SP", "SP", "SP", "SP", "SP", "S…
$ `Inicio Operação` <chr> "01/01/2007", "01/01/2007", "01/01/2007", "0…
$ `Fim Operação` <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ Latitude <chr> "23 43 04", "23 43 04", "23 43 04", "23 43 0…
$ Longitude <chr> "46 39 51", "46 39 51", "46 39 51", "46 39 5…
$ Altitude <chr> "743", "743", "743", "743", "743", "743", "7…
$ Localização <chr> "No meio do corpo central, cerca de 1,5 km d…
$ Captação <chr> "N", "N", "N", "N", "N", "N", "N", "N", "N",…
purrr
is a very powerful package!
I use it a lot in my daily tasks!
Today, I focused on helping you to understand the basics to start using purrr
. But there is other functions that you can learn!
Video: Hadley Wickham | {purrr} 1.0: A complete and consistent set of tools for functions and vectors
Slides por Beatriz Milz (@BeaMilz), feito com Quarto e Quarto R-Ladies Theme.