Anexo 4: Controle de Fluxo e Funções em R
Conteúdo:
- Funções em R
- O que são Funções?
- Parâmetros (Argumentos)
- Retorno de Valores
- Blocos de Código
if
(Condicionais) - Controle de Fluxo com Loops:
for
,while
erepeat
- modo base:
apply
,lapply, tapply
esapply
- purr tidyverse:
map
,walk,etc..
O que são Funções
Funções são blocos de código que executam uma tarefa específica e podem ser reutilizados em diferentes partes do seu programa. Elas são Com elas que você pode criar para automatizar processos, tornando seu código mais organizado, eficiente e fácil de manter evitando retrabalho.
Nós interagimos com funções o tempo inteiro no R quase tudo que você faz é usar funções e especificar parâmetros.
Uma função básica em R tem os seguintes elementos:
nome_da_funcao
: É o nome que você dá à sua função para poder chamá-la depois.function()
: É a palavra-chave que indica a criação de uma função.(argumentos)
: São os valores que a função recebe para trabalhar. Eles são opcionais.{corpo_da_funcao}
: É o bloco de código dentro das chaves ({}
) que contém as instruções a serem executadas.return()
: É a instrução que especifica o valor que a função deve retornar como resultado. No R, a última expressão avaliada no corpo da função é retornada automaticamente, então oreturn()
é opcional, mas é uma boa prática para clareza.
Vamos construir uma função que transforma uma temperatura em graus Fahrenheit para graus celsius.
A fórmula para converter a temperatura é:
\[ C = \frac{(F - 32) * 5} {9} \]
Vamos chamar a nossa função conv_c2c
(existe uma série de recomendações sobre como dar nome a funções). A função vai receber um parâmetro temp_f
com a temperatura a ser convertida e retorna rum valor com a temperatura em Celsius.
<- function(temp_f) {
conv_f2c # O argumento 'f' representa a temperatura em Fahrenheit.
# Aplica a fórmula de conversão
<- (temp_f - 32) * (5/9)
temp_c
# Retorna o valor em Celsius
return(temp_c)
}
Escopo de Variáveis em Funções
O escopo de uma variável determina onde ela pode ser acessada. Em R, as variáveis definidas dentro de uma função têm escopo local, o que significa que elas só podem ser acessadas dentro da função. Variáveis definidas fora de uma função têm escopo global e podem ser acessadas em qualquer lugar do código.
# Variavel global
<- 10
x
<- function() {
minha_funcao # Variavel local
<- x/2
y print(x) # Acessa a variavel global x
print(y)
}
minha_funcao() # Saída: 10, 5
# print(y)# Erro: y não está definido fora da função
Uma função deve receber os argumentos necessários a sua execução. As variáveis internas a função só existem dentro do espaço da função. A função retorna apenas um valor que pode ser qq tipo de dado.
Vantagens de usar funções
Reusabilidade: Você escreve o código uma vez e pode usá-lo várias vezes, evitando repetição de código.
Organização: Funções dividem seu código em partes lógicas e gerenciáveis.
Facilidade de manutenção: Se você precisar corrigir ou melhorar um pedaço do seu código, só precisa fazer a alteração na função, e não em todos os lugares onde o código foi repetido.
Legibilidade: O código se torna mais fácil de ler e entender, pois o nome da função já descreve o que ela faz.
Debug: Possibilidade de depurar o código inspecionando o seu funcionamento passo a passo.
Blocos de Código if (Condicionais)
Os blocos if permitem que você execute diferentes partes do código com base em uma condição. o blocos {} delimitam o bloco de código que será executado se a condição do if for verdadeira.
if (condição) {
# Código a ser executado se a condição for verdadeira
else {
} # Código a ser executado se a condição for falsa (opcional)
}
Analise o código abaixo
<- 20
idade
if (idade >= 18) {
print("Você é maior de idade.")
print("você já pode dirigir")
else {
} print("Você é menor de idade.")
}
As chaves {}
são essenciais quando você tem mais de uma instrução a ser executada dentro do bloco if. Sem as chaves, apenas a primeira instrução após o if é considerada parte do bloco, o que pode levar a erros. Mesmo com uma única instrução, usar chaves melhora a legibilidade do código. As condições dentro do IF podem ser complexas usando os demais operadores lógicos.
O controle de fluxo por laços
As estruturas for, while e repeat são as principais ferramentas em R para criar laços de repetição (ou loops), que são usados para executar um bloco de código várias vezes.
O for
for é ideal quando você sabe exatamente quantas vezes a repetição precisa ocorrer. Ele itera sobre uma sequência de itens, como um vetor, uma lista ou uma coluna de um data frame, executando o código para cada item.
for (item in sequencia) {
# Código a ser executado
}
por exemplo:
<- c(1, 3, 5, 7, 9 )
numeros
for (n in numeros) {
<- n^2
quadrado print(paste("O quadrado de", n, "é", quadrado))
}
o for
é laço mais comum e seguro, pois evita loops infinitos. É a melhor escolha para a maioria das tarefas de iteração. em sua forma geral temos:
while (condicao) {
# Código a ser executado
}
<- 5
contador
while (contador > 0) {
print(contador)
<- contador - 1 # É crucial alterar a variável para evitar um loop infinito
contador
}print("Contador chegou a ZERO!")
O while
útil quando você não sabe o número exato de repetições, mas sabe qual condição deve ser satisfeita para que o loop pare.
o repeat
executa um bloco de código indefinidamente até que seja explicitamente interrompido. Você deve usar uma instrução break dentro do laço para parar a execução, baseada em uma condição. Se não houver break, o loop será infinito.
repeat {
# Código a ser executado
if (condicao_de_parada) {
break
} }
<- c(3, 7, 9, 12, 5, 15)
numeros <- 1
i
repeat {
<- numeros[i]
numero_atual
if (numero_atual > 10) {
print(paste("O primeiro número maior que 10 é", numero_atual))
break # Sai do loop
}
<- i + 1
i }
O repeat
útil para situações onde a condição de saída pode estar no meio do bloco de código, ou quando você precisa garantir que o laço execute pelo menos uma vez. No entanto, é mais propenso a erros (como loops infinitos) e geralmente menos usado que o for e o while.
Em resumo:
for | while | repeat | |
---|---|---|---|
Interações | conhecida | condicional | indefinida (break) |
condição parada | sequencia definida | condição é FALSA | comando break |
uso tipico | iteragir em uma sequencia | repetir até condição | simulações, eventos do sistema |
Familia apply
No R BASE, as funções apply
, lapply
e sapply
são ferramentas poderosas para aplicar uma função a uma estrutura de dados (como um vetor, matriz, lista ou data frame) sem a necessidade de escrever um loop explícito. Elas são fundamentais para programação funcional e para tornar o código mais rápido conciso e eficiente.
1. apply()
- Finalidade: Aplica uma função a cada linha ou coluna de uma matriz ou array.
- Estrutura:
apply(X, MARGIN, FUN, ...)
.X
: A matriz, array ou data frame a ser processado.MARGIN
: Especifica se a função deve ser aplicada a:1
: Linhas.2
: Colunas.
FUN
: A função a ser aplicada....
: Argumentos adicionais a serem passados para a funçãoFUN
.
- Retorno: Depende da função
FUN
e da estrutura de dadosX
. Pode ser um vetor, matriz, lista ou outra estrutura de dados. - Exemplo:
# Criando uma matriz
<- matrix(1:9, nrow = 3, ncol = 3)
matriz
matriz
# Aplicando a função 'mean' a cada linha
apply(matriz, 1, mean)
# Aplicando a função 'sum' a cada coluna
apply(matriz, 2, sum)
2. lapply()
- Finalidade: Aplica uma função a cada elemento de uma lista.
- Estrutura:
lapply(X, FUN, ...)
X
: A lista a ser processada.FUN
: A função a ser aplicada....
: Argumentos adicionais a serem passados para a funçãoFUN
.
- Retorno: Sempre retorna uma lista, mesmo que a função
FUN
retorne valores que poderiam ser combinados em um vetor ou matriz. - Exemplo:
# Criando uma lista
<- list(c(1, 2, 3), c(4, 5, 6), c(7, 8, 9))
minha_lista
# Aplicando a função 'length' a cada elemento da lista
<- lapply(minha_lista, length)
comprimentos print(comprimentos)
3. sapply()
- Finalidade: Semelhante a
lapply()
, mas tenta simplificar a saída. Aplica uma função a cada elemento de uma lista e tenta simplificar a saída para um vetor ou matriz, se possível. - Estrutura:
sapply(X, FUN, ..., simplify = TRUE, USE.NAMES = TRUE)
X
: A lista a ser processada.FUN
: A função a ser aplicada....
: Argumentos adicionais a serem passados para a funçãoFUN
.simplify
: Um argumento lógico (TRUE por padrão). Se TRUE, tenta simplificar a saída. Se FALSE, o comportamento é idêntico alapply
.USE.NAMES
: Um argumento lógico (TRUE por padrão). Se TRUE, os nomes dos elementos da lista de entrada são preservados na lista de saída (se possível).
- Retorno: Pode retornar um vetor, matriz, lista ou outra estrutura de dados, dependendo do resultado da função
FUN
. - Exemplo:
# Criando uma lista
<- list(c(1, 2, 3), c(4, 5, 6), c(7, 8, 9))
minha_lista
# Aplicando a função 'length' a cada elemento da lista
<- sapply(minha_lista, length)
comprimentos print(comprimentos)
Principais Diferenças e Quando Usar:
apply()
: Ideal para trabalhar com matrizes e arrays, permitindo aplicar funções a linhas ou colunas.lapply()
: Use quando você precisa aplicar uma função a cada elemento de uma lista e sempre precisa de uma lista como resultado. É uma boa escolha quando você não tem certeza sobre o tipo de saída da função que está aplicando.sapply()
: Use quando você quer aplicar uma função a uma lista e obter uma saída simplificada (vetor ou matriz) sempre que possível. Se a funçãoFUN
retornar resultados de tamanhos diferentes,sapply
ainda retornará uma lista. É um atalho conveniente para usarlapply
e, em seguida, tentar simplificar o resultado.
Em resumo:
Característica | apply() |
lapply() |
sapply() |
---|---|---|---|
Estrutura de Dados | Matrizes, arrays | Listas | Listas |
Retorno | Depende da função e da estrutura de dados | Sempre uma lista | Tenta simplificar para vetor/matriz |
Foco | Aplicar a linhas/colunas | Aplicar a cada elemento (lista) | Aplicar e simplificar |
Dominar essas funções é fundamental para escrever código R mais eficiente e elegante. Experimente com diferentes funções e estruturas de dados para entender completamente como elas funcionam.
Pacote `purr’do tidyverse
As funções map
e walk
do pacote purrr
em R são alternativas modernas e expressivas às funções lapply
, sapply
e walk
do R base. O purrr
faz parte do ecossistema tidyverse
, que enfatiza a clareza, a consistência e a legibilidade do código. Elas oferecem recursos adicionais e uma sintaxe mais intuitiva para trabalhar com listas e vetores.
1. map()
Finalidade: Aplica uma função a cada elemento de um vetor, lista ou tibble. É a alternativa mais direta para
lapply
esapply
.Estrutura:
map(x, f, ..., .x = NULL, .y = NULL, by = NULL, .keep = NULL, .call = NULL)
x
: O vetor, lista ou tibble a ser processado.f
: A função a ser aplicada....
: Argumentos adicionais a serem passados para a funçãof
..x
,.y
: Nomes padrão dos argumentos que recebem o vetor/lista original e o índice (opcional).by
: Permite aplicar a função a subconjuntos dos dados..keep
: Especifica quais nomes devem ser mantidos na lista de saída..call
: Permite usar uma expressão como a função a ser aplicada (menos comum).
Variações:
map_lgl()
,map_int()
,map_dbl()
,map_chr()
,map_logl()
,map_int()
,map_dbl()
,map_chr()
. Essas variações forçam o tipo de saída da funçãof
para lógico, inteiro, numérico (double) e caracter, respectivamente. Isso ajuda a evitar ambiguidades e garante que a saída seja do tipo esperado.Retorno: Sempre retorna uma lista, a menos que você use uma das variantes que forçam um tipo específico (como
map_dbl
, que retorna um vetor numérico).Exemplo:
library(purrr)
# Criando uma lista
<- list(c(1, 2, 3), c(4, 5, 6), c(7, 8, 9))
minha_lista
# Aplicando a função 'length' a cada elemento da lista
<- map(minha_lista, length)
comprimentos print(comprimentos)
# Forçando o tipo de saída para numérico
<- map_dbl(minha_lista, length)
comprimentos_num print(comprimentos_num)
2. walk()
Finalidade: Aplica uma função a cada elemento de um vetor, lista ou tibble e não retorna nada. É projetada para efeitos colaterais, como imprimir resultados, escrever em arquivos ou atualizar gráficos. É uma alternativa à função
for
(embora geralmente mais legível).Estrutura:
walk(x, f, ..., .x = NULL, .y = NULL)
x
: O vetor, lista ou tibble a ser processado.f
: A função a ser aplicada....
: Argumentos adicionais a serem passados para a funçãof
..x
,.y
: Nomes padrão dos argumentos que recebem o vetor/lista original e o índice (opcional).
Variações:
walk_list()
,walk2()
,walk_along()
.walk_list()
retorna uma lista dos resultados da função aplicada (útil em alguns casos), enquantowalk2()
aplica a função a dois vetores/listas simultaneamente.walk_along()
itera sobre os elementos de um vetor ou lista, em vez de sobre os nomes.Retorno:
NULL
. A função é utilizada apenas pelos seus efeitos colaterais.Exemplo:
library(purrr)
# Criando uma lista
<- list(c(1, 2, 3, 5, 10), c(9, 5, 7, 4), c(11, 8))
minha_lista
# Imprimindo o comprimento de cada elemento da lista
walk(minha_lista, function(x) length(x)))
Principais Diferenças e Vantagens de purrr
:
- Clareza e Consistência: O
purrr
segue uma filosofia de design consistente, tornando o código mais fácil de entender e manter. - Nomes de Argumentos Padrão: Os nomes de argumentos
.x
e.y
tornam mais claro qual argumento recebe o elemento atual e qual recebe o índice (se você precisar dele). - Forçamento de Tipos de Dados: As variantes
map_lgl()
,map_int()
,map_dbl()
,map_chr()
e também omap_db
que forçam o tipo de dados da saída, evitando ambiguidades e facilitando o debugging. - Efeitos Colaterais Explícitos:
walk()
é projetada especificamente para efeitos colaterais, o que torna o código mais legível e fácil de entender. - Integração com
tidyverse
: Opurrr
se integra perfeitamente com outras funções dotidyverse
, facilitando a criação de pipelines de dados elegantes e eficientes. - Mais Expressivo: Em muitos casos, o
purrr
oferece uma sintaxe mais concisa e expressiva do que as funções do R base.
Quando Usar:
map()
: Substituilapply
esapply
quando você precisa aplicar uma função a uma lista ou vetor e precisa de uma lista como resultado ou quer forçar o tipo de saída.walk()
: Use em vez de loopsfor
quando você precisa executar uma ação (efeito colateral) para cada elemento de uma lista ou vetor.- Em geral: Se você estiver trabalhando com o
tidyverse
, usarpurrr
é altamente recomendado para consistência e clareza do código.
O purrr
é uma adição valiosa ao seu arsenal de ferramentas em R, especialmente se você valoriza a clareza, a consistência e a legibilidade do código.