flowchart LR A[Entrada_1 <br> Entrada_2 <br> ... <br> Entrada_k] --> B(((Processamento))) B --> C[Resultado_1 <br> Resultado_2 <br> ... <br> Resultado_k]
Análise de Dados Financeiros e Econômicos com o R (Perlin 2021, cap 08)
EA-UFRGS
24/09/2026
Ao final desta aula, você será capaz de:
if/else)purrrdplyrProgramação é a execução de um conjunto de instruções complexas ao computador, as quais solucionam algum problema de análise de dados
permite iterações sequenciais, encapsulamento de métodos, e automatização de qualquer procedimento computacional
Em resumo, o computador será uma poderosa e escalável extensão do seu cérebro
Everything that exists is an object. Everything that happens is a function call — John Chambers, creator of the S language, the predecessor to R.
flowchart LR A[Entrada_1 <br> Entrada_2 <br> ... <br> Entrada_k] --> B(((Processamento))) B --> C[Resultado_1 <br> Resultado_2 <br> ... <br> Resultado_k]
flowchart LR A[<b> Entradas:</b> <br><br>Ano de Nascimento <br> Ano Atual] --> B(((<b>Processamento:</b><br><br>Ano atual menos nascimento))) B --> C[<b>Saída:</b> <br><br> Idade Atual]
my_fct <- function(arg1 = 1, arg2 = 'abc'){
length_arg1 <- length(arg1)
length_arg2 <- length(arg2)
msg1 <- paste0('Number of elements in arg1: ', length_arg1)
message(msg1)
msg2 <- paste0('Number of elements in arg2: ', length_arg2)
message(msg2)
out <- c(length_arg1, length_arg2)
return(out)
}
out1 <- my_fct(arg1 = 2, arg2 = 'bcd')
print(out1)[1] 1 1
[1] 10 2
Vamos criar uma função que calcule, para qualquer ação do Yahoo Finance (
yfR), o retorno acumulado entre 2015 e a data atual
Testando a função:
Utilizados de forma ostensiva na análise de dados, os loops permitem a repetição estruturada de códigos e possibilitam o processamento de itens individualmente de uma forma fácil.
A estrutura de um loop segue o seguinte esqueleto de código:
O uso de loops encadeados, isto é, um loop dentro de outro loop, também é possível. Veja o exemplo a seguir, onde apresentamos todos os elementos de uma matriz:
PETR4.SA GRND3.SA WEGE3.SA AMER3.SA ^BVSP
20.1533378 1.0704272 9.8883402 -0.9974928 2.8302688
MMM AOS ABT ABBV ACN
0.7969428 1.5011226 1.8944848 5.4466193 1.5224930
library(dplyr)
# read data
my_f <- afedR3::data_path('CH08_some-stocks-SP500.csv')
my_df <- readr::read_csv(my_f)
# find unique tickers in column ticker
unique_tickers <- unique(my_df$ticker)
# create empty df
tab_out <- tibble()
# loop tickers
for (i_ticker in unique_tickers){
# create temp df with ticker i_ticker
temp_df <- my_df |>
filter(ticker == i_ticker)
temp_mean_price <- mean(temp_df$price_adjusted)
temp_last_date <- dplyr::last(temp_df$ref_date)
tibble_temp <- tibble(ticker = i_ticker,
mean_price = temp_mean_price,
last_date = temp_last_date)
tab_out <- bind_rows(tab_out,
tibble_temp)
}
# print result
print(tab_out[1:10, ])# A tibble: 10 × 3
ticker mean_price last_date
<chr> <dbl> <date>
1 BA 256. 2022-12-30
2 CMI 180. 2022-12-30
3 DE 238. 2022-12-30
4 FCX 22.2 2022-12-30
5 K 59.4 2022-12-30
6 MSI 170. 2022-12-30
7 NTRS 92.3 2022-12-30
8 PNR 47.2 2022-12-30
9 SEDG 169. 2022-12-30
10 SWK 140. 2022-12-30
Dica de desempenho
Crescer tab_out com bind_rows a cada iteração funciona, mas é ineficiente. Em produção, colete os resultados em uma lista e combine-os uma única vez ao final do loop (ou use purrr::map() combinado com dplyr::bind_rows()).
if, else, switch)Execuções condicionais permitem tomar decisões binárias no código, do tipo se, então (if, then)
Podemos, também, aplicar mais de uma condição lógica com o comando else e else if. Veja a seguir:
Programação funcional é o uso exclusivo de funções para resolver algum problema de análise de dados.
Versão com loop
base oferece funções nativas da família apply: sapply, lapply, tapply, mapply, apply e by.tidyverse, programação funcional é oferecida pelo pacote purrr (Wickham and Henry 2026)purrrpurrrPrincipais funções:
map(): retorna sempre uma listamap_dbl(): retorna sempre um vetor numérico (double)map_int(): retorna sempre um vetor de inteiros (integer)map_chr(): retorna sempre um vetor de texto (character)map_lgl(): retorna sempre um vetor lógico (logical)pmap(): retorna uma lista, mas com entrada flexível de argumentos vec1 vec2 vec3 char1
10 50 5 10
vec1 vec2 vec3 char1
FALSE FALSE FALSE TRUE
Outro ponto interessante nas funções do purrr é que permitem, de uma forma simples, o acesso a elementos de uma lista. Para isso, basta indicar uma entrada de posição ou nome na função map:
$vec1
[1] 20
$char1
[1] 50
$vec1
[1] 5
$char1
[1] 15
permite o controle e tratamento de erros de execução
Exemplo:
Error in `x + 1`:
! non-numeric argument to binary operator
Agora vamos utilizar safely para encapsular add_one em outra função chamada add_one_safely:
$result
NULL
$error
<simpleError in x + 1: non-numeric argument to binary operator>
Um exemplo de uso completo:
[[1]]
[[1]]$result
[1] 2 3 4 5 6
[[1]]$error
NULL
[[2]]
[[2]]$result
NULL
[[2]]$error
<simpleError in x + 1: non-numeric argument to binary operator>
[[3]]
[[3]]$result
[1] 2 3 4 5
[[3]]$error
NULL
Podemos facilmente ver que a função teve erro no segundo elemento de my_l. Indo além, caso quiséssemos apenas os resultados, podemos escrever:
Ou apenas as mensagens de erro:
[[1]]
NULL
[[2]]
<simpleError in x + 1: non-numeric argument to binary operator>
[[3]]
NULL
A saída padrão para o caso de erros também pode ser modificada. Veja o próximo caso, onde inserimos o valor NA toda vez que a função resultar em erro (argumento otherwise), e retornamos um vetor:
purrr::map_* permitem a passagem de apenas um argumento dinâmico (que muda) em cada chamada da funçãopmap permite passar qualquer número de argumentos para uma função de destino, inclusive replica loops aninhados.Como exemplo, vamos considerar uma função que cria uma frase a partir de três entradas:
[1] "My name is Joe and I like to eat apple while studying."
Usando loops aninhados, escrevemos o seguinte código:
names_vec <- c('Joe', 'Kate')
fruits_vec <- c('kiwi', 'apple')
verb_vec <- c('rowing', 'studying')
my_phrases <- character()
for (i_name in names_vec) {
for (i_fruit in fruits_vec) {
for (i_verb in verb_vec) {
my_phrases <- c(my_phrases,
build_phrase(i_name, i_fruit, i_verb))
}
}
}
print(my_phrases)[1] "My name is Joe and I like to eat kiwi while rowing."
[2] "My name is Joe and I like to eat kiwi while studying."
[3] "My name is Joe and I like to eat apple while rowing."
[4] "My name is Joe and I like to eat apple while studying."
[5] "My name is Kate and I like to eat kiwi while rowing."
[6] "My name is Kate and I like to eat kiwi while studying."
[7] "My name is Kate and I like to eat apple while rowing."
[8] "My name is Kate and I like to eat apple while studying."
Embora o código funcione conforme o esperado, uma melhor abordagem é usar purrr::pmap. Tudo o que precisamos fazer é passar todas as combinações de argumentos para a função:
[1] "My name is Joe and I like to eat kiwi while rowing."
[2] "My name is Joe and I like to eat kiwi while studying."
[3] "My name is Joe and I like to eat apple while rowing."
[4] "My name is Joe and I like to eat apple while studying."
[5] "My name is Kate and I like to eat kiwi while rowing."
[6] "My name is Kate and I like to eat kiwi while studying."
[7] "My name is Kate and I like to eat apple while rowing."
[8] "My name is Kate and I like to eat apple while studying."
dplyr (Wickham et al. 2026)tidyversedplyr permite a realização de análises complexas do tipo split-apply-combine com uma sintaxe simples e intuitiva.dplyrEtapas:
vamos calcular a média, desvio padrão, máximo e mínimo dos retornos de um grupo de ações
library(dplyr)
tickers <- c("PETR4.SA", "VALE3.SA", "GRND3.SA")
first_date <- "2018-01-01"
tbl_yf <- yfR::yf_get(tickers, first_date) |>
na.omit() |>
group_by(ticker) |>
summarise(ret_mean = mean(ret_adjusted_prices),
ret_sd = sd(ret_adjusted_prices),
ret_max = max(ret_adjusted_prices),
ret_min = min(ret_adjusted_prices))
tbl_yf# A tibble: 3 × 5
ticker ret_mean ret_sd ret_max ret_min
<chr> <dbl> <dbl> <dbl> <dbl>
1 GRND3.SA 0.000181 0.0204 0.0990 -0.112
2 PETR4.SA 0.00149 0.0258 0.222 -0.297
3 VALE3.SA 0.000809 0.0221 0.214 -0.246
# A tibble: 15 × 6
# Groups: ticker [3]
ticker weekday ret_mean ret_sd ret_max ret_min
<chr> <chr> <dbl> <dbl> <dbl> <dbl>
1 GRND3.SA Friday -0.000466 0.0230 0.0811 -0.111
2 GRND3.SA Monday -0.000981 0.0204 0.0990 -0.112
3 GRND3.SA Thursday -0.000210 0.0191 0.0788 -0.0792
4 GRND3.SA Tuesday 0.00160 0.0188 0.0775 -0.0542
5 GRND3.SA Wednesday 0.000953 0.0203 0.0871 -0.0782
6 PETR4.SA Friday -0.000988 0.0261 0.222 -0.149
7 PETR4.SA Monday 0.00168 0.0308 0.110 -0.297
8 PETR4.SA Thursday 0.000472 0.0239 0.0846 -0.205
9 PETR4.SA Tuesday 0.00407 0.0236 0.152 -0.0680
10 PETR4.SA Wednesday 0.00218 0.0237 0.0816 -0.132
11 VALE3.SA Friday 0.00109 0.0239 0.214 -0.0683
12 VALE3.SA Monday 0.000672 0.0240 0.0668 -0.246
13 VALE3.SA Thursday -0.000566 0.0191 0.0653 -0.132
14 VALE3.SA Tuesday 0.00252 0.0217 0.185 -0.0548
15 VALE3.SA Wednesday 0.000356 0.0216 0.0903 -0.0954
for) repetem instruções de forma dinâmica e são úteis para processar grupos de dadosif/else) permitem tomar decisões no códigopurrr) substitui loops por map_*/pmap_*dplyr resolve split-apply-combine com group_by() + summarise()Crie uma função chamada say_my_name() que tome como entrada um nome de pessoa e mostre na tela o texto Your name is …. Dentro do escopo da função, utilize comentários para descrever o propósito da função, suas entradas e saídas.
Implemente um teste para os objetos de entrada, de forma que, quando o nome de entrada não for da classe character, um erro é retornado ao usuário. Teste sua nova função e verifique se a mesma está funcionando conforme esperado.
Crie um vetor com cinco nomes quaisquer, chamado my_names. Utilizando um loop, aplique função say_my_name para cada elemento de my_names.
No banco de dados do Brasil.IO1 encontrarás uma tabela com nomes e gêneros derivados de uma das pesquisas do IBGE. Importe os dados do arquivo para R e, usando um loop, aplique a função say_my_name a 15 nomes aleatórios do banco de dados. Dica: neste caso, você pode baixar os dados direto do link usando readr::read_csv(LINK).
Use o pacote yfR para baixar dados do índice SP500 ('^GSPC'), Ibovespa ('^BVSP'), FTSE ('^FTSE') e Nikkei 225 ('^N225') de '2010-01-01' até a data atual. Com os dados importados, use um loop para calcular o retorno médio, máximo e mínimo de cada índice durante o período analisado. Salve todos os resultados em uma tabela única e a mostre no prompt do R.
Refaça o exercício anterior utilizando as funções group_by e summarise, ambas do pacote dplyr.
No site do RStudio CRAN logs você encontrará dados sobre as estatísticas de download para a distribuição de base de R na seção Daily R downloads. Usando suas habilidades de programação, importe os dados disponíveis entre 2015-01-01 e 2026-09-24 e agregue-os em uma única tabela. Qual país apresenta a maior contagem de downloads do R? NOTA 1: para viabilizar o exercício, comece importando apenas um período curto (por exemplo, um único mês) antes de expandir para todos os arquivos. NOTA 2: caso tiver erro no download, ignore os arquivos com falha, e continue a importação e análise dos demais. Podes usar purrr::safely para tratar erros no código.
ADFER - UFRGS