→ FUNÇÕES ←
São elementos de primeira ordem
- Atribuí-las a variáveis
- Guardá-las em listas
- Passá-las como argumentos
- Criá-las dentro de outra função
- Retorná-las como resultado de uma outra função
Blocos básicos
- Funções anônimas
- Closures (funções escritas por outras funções)
- Listas de funções
Arquivo que usa -99
para representar valores ausentes.
library(tidyverse)
library(xtable);
set.seed(42)
df <- data.frame(
replicate(6, sample(c(1:10, -99), 6, rep = TRUE)))
names(df) <- letters[1:6];
xtable(df, size="\\small")
Objetivo: substituir -99
por NA
. Como fazer?
Onde estão os erros semânticos?
df$a[df$a == -99] <- NA
df$b[df$b == -99] <- NA
df$c[df$c == -98] <- NA
df$d[df$d == -99] <- NA
df$e[df$e == -99] <- NA
df$f[df$g == -99] <- NA
fix_missing <- function(x) {
x[x == -99] <- NA
x
}
df$a <- fix_missing(df$a)
df$b <- fix_missing(df$b)
df$c <- fix_missing(df$c)
df$d <- fix_missing(df$d)
df$e <- fix_missing(df$e)
df$f <- fix_missing(df$e)
Utilizar duas funções
fix_missing
sabe como substituir-99
porNA
lapply
sabe como aplicar algo para cada coluna do DF- Recebe três argumentos: lista, função, argumentos para a função
A Função lapply
é um exemplo de funcional
(uma função que recebe outra função)
fix_missing <- function(x) {
x[x == -99] <- NA
x
}
# Aplicando para todas as colunas
df[] <- lapply(df, fix_missing)
# Aplicando para somente as cinco primeiras colunas
df[1:5] <- lapply(df[1:5], fix_missing)
df;
a b c d e f 1 NA 9 NA 6 1 9 2 NA 2 3 7 6 9 3 4 8 6 10 5 5 4 10 8 NA 2 10 8 5 8 6 NA NA 5 1 6 6 8 2 NA 10 10
Ideia chave: composição de funções.
… os valores ausentes são representados por vários valores.
Solução ingênua: copiar/colar → criador de problemas
Solução melhor:
Utilizar uma função que cria outras funções (closure).
missing_fixer <- function(na_value) {
function(x) {
x[x == na_value] <- NA
x
}
}
fix_missing_99 <- missing_fixer(-99)
fix_missing_999 <- missing_fixer(-999)
Declarando
function(x) x*x
Todas as funções tem formals
, body
, e um environment
.
formals( function(x) x*x )
body( function(x) x*x )
environment( function(x) x*x )
$x x * x <environment: R_GlobalEnv>
É obrigatório o uso dos parênteses
- Para chamar a função
- Para passar argumentos
( function(x) x*x ) (2)
# faz a mesma coisa que o seguinte
f <- function(x) x*x
f(2);
[1] 4 [1] 4
“An object is data with functions. A closure is \linebreak a function with data.” — John D. Cook
Funções anônimas
- Definir pequenas funções que não merecem um nome
- Criar Closures
Elas levam consigo o escopo/ambiente de onde foram definidas
power <- function(exponent) {
function(x) {
x ^ exponent
}
}
square <- power(2)
cube <- power(3)
square
function(x) { x ^ exponent } <environment: 0x55d41594eec8>
cube
function(x) { x ^ exponent } <environment: 0x55d41594e178>
O que mudou?
as.list(environment(square))
$exponent [1] 2
as.list(environment(cube))
$exponent [1] 3
Modificar valores no ambiente do pai; permite criar estados mutáveis.
- Uma closure leva consigo o escopo/ambiente de onde foi definida.
new_counter <- function() {
i <- 0
function() {
i <<- i + 1
i
}
}
counter_one <- new_counter()
counter_two <- new_counter()
counter_one()
counter_one()
counter_two()
[1] 1 [1] 2 [1] 1
Funções podem ser mantidas em listas.
(chamá-las em um único comando com lapply
)
Vejamos uma lista com três formas de calcular a média de um vetor.
compute_mean <- list(
base = function(x) mean(x),
sum = function(x) sum(x) / length(x),
manual = function(x) {
total <- 0
n <- length(x)
for (i in seq_along(x)) {
total <- total + x[i] / n
}
total
}
)
Obter uma referência a ela, e em seguida realizar a chamada.
x <- runif(1e7)
system.time(compute_mean$base(x))
system.time(compute_mean[[2]](x))
system.time(compute_mean[["manual"]](x))
Chamar todas elas com a função lapply
# Primeira forma
lapply(compute_mean, function(f) f(x))
# Segunda forma
call_fun <- function(f, ...) f(...)
lapply(compute_mean, call_fun, x)
Sendo assim, podemos
lapply(compute_mean, function(f) system.time(f(x)))
# E passar parâmetros com valores "fixos"
lapply(compute_mean, function(f) f(x))#, na.rm = TRUE))
- Capítulo sobre Functional Programming