Rows: 10
Columns: 2
$ x <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
$ y <chr> "l", "j", "p", "v", "e", "w", "c", "o", "q", "k"
Análise de Dados Financeiros e Econômicos com o R
EA-UFRGS
10/09/2026
dataframes e lists são os objetos mais usados no R
dataframeoutibblesignifica “estrutura ou organização de dados”. Grosso modo, um objeto da classe dataframe nada mais é do que uma tabela, com linhas e colunas.
dataframe é um tipo especial de lista, onde cada coluna é um vetor atômico com o mesmo número de elementos, porém com sua própria classe.dataframesRows: 10
Columns: 2
$ x <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
$ y <chr> "l", "j", "p", "v", "e", "w", "c", "o", "q", "k"
# set tickers
ticker <- c(rep('ABEV3',4),
rep('BBAS3', 4),
rep('BBDC3', 4))
# set dates
ref_date <- as.Date(rep(c('2010-01-01', '2010-01-04',
'2010-01-05', '2010-01-06'),
3) )
# set prices
price <- c(736.67, 764.14, 768.63, 776.47,
59.4 , 59.8 , 59.2 , 59.28,
29.81 , 30.82 , 30.38 , 30.20)
# create tibble/dataframe
my_df <- dplyr::tibble(
ticker,
ref_date,
price
)
# print it
print(my_df)# A tibble: 12 × 3
ticker ref_date price
<chr> <date> <dbl>
1 ABEV3 2010-01-01 737.
2 ABEV3 2010-01-04 764.
3 ABEV3 2010-01-05 769.
4 ABEV3 2010-01-06 776.
5 BBAS3 2010-01-01 59.4
6 BBAS3 2010-01-04 59.8
7 BBAS3 2010-01-05 59.2
8 BBAS3 2010-01-06 59.3
9 BBDC3 2010-01-01 29.8
10 BBDC3 2010-01-04 30.8
11 BBDC3 2010-01-05 30.4
12 BBDC3 2010-01-06 30.2
dataframeAtenção!
Inspecionar tabelas é uma das artes em análise de dados, exigindo intimidade com os dados e o problema em questão.
Estamos interessados em:
NA)dplyr::glimpse()Rows: 12
Columns: 3
$ ticker <chr> "ABEV3", "ABEV3", "ABEV3", "ABEV3", "BBAS3", "BBAS3", "BBAS3"…
$ ref_date <date> 2010-01-01, 2010-01-04, 2010-01-05, 2010-01-06, 2010-01-01, …
$ price <dbl> 736.67, 764.14, 768.63, 776.47, 59.40, 59.80, 59.20, 59.28, 2…
base::summary() ticker ref_date price
Length :12 Min. :2010-01-01 Min. : 29.81
N.unique : 3 1st Qu.:2010-01-03 1st Qu.: 30.71
N.blank : 0 Median :2010-01-04 Median : 59.34
Min.nchar: 5 Mean :2010-01-04 Mean :283.73
Max.nchar: 5 3rd Qu.:2010-01-05 3rd Qu.:743.54
Max. :2010-01-06 Max. :776.47
skimr::skim()| Name | my_df |
| Number of rows | 12 |
| Number of columns | 3 |
| _______________________ | |
| Column type frequency: | |
| character | 1 |
| Date | 1 |
| numeric | 1 |
| ________________________ | |
| Group variables | None |
Variable type: character
| skim_variable | n_missing | complete_rate | min | max | empty | n_unique | whitespace |
|---|---|---|---|---|---|---|---|
| ticker | 0 | 1 | 5 | 5 | 0 | 3 | 0 |
Variable type: Date
| skim_variable | n_missing | complete_rate | min | max | median | n_unique |
|---|---|---|---|---|---|---|
| ref_date | 0 | 1 | 2010-01-01 | 2010-01-06 | 2010-01-04 | 4 |
Variable type: numeric
| skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
|---|---|---|---|---|---|---|---|---|---|---|
| price | 0 | 1 | 283.73 | 353.17 | 29.81 | 30.71 | 59.34 | 743.54 | 776.47 | ▇▁▁▁▃ |
Desafio em aula
Olhe atentamente para a tabela abaixo. Quantos problemas de estrutura ou consistência de dados você consegue identificar antes de avançar?
| Data | id.candidato | Nome do candidato | Profissão | age | ano_casamento |
|---|---|---|---|---|---|
| 10/09/2026 | 1 | Y | professor | 8 | 1999 |
| 10/09/2026 | 1 | D | professor | -1 | 2010 |
| 10/09/2026 | 1 | G | professor | 9 | 1995 |
| 10/09/2026 | 1 | A | casado | -4 | 2004 |
| 10/09/2026 | 1 | B | advogado | 4 | 2001 |
| 10/09/2026 | 1 | K | casado | 3 | 1998 |
| 10/09/2026 | 1 | N | advogado | -5 | 1996 |
| 10/09/2026 | 1 | R | advogado | -2 | 2008 |
| 10/09/2026 | 1 | W | advogado | -3 | 2005 |
| 10/09/2026 | 1 | J | advogado | 0 | 1997 |
Data em formato local (dd/mm/yyyy)id.candidato tem somente valor 1Nome do Candidato tem espaço no nome da coluna, e valores que não fazem sentidoProfissão tem caractere especial e valor “casado”, o qual não faz sentidoage está em inglês e apresenta valores negativos (ex: -5)dataframedataframe possui notação matricial para elementos individuais ou blocosExistem duas principais maneiras de acessar uma coluna de um dataframe via nome:
[1] "ABEV3" "ABEV3" "ABEV3" "ABEV3" "BBAS3" "BBAS3" "BBAS3" "BBAS3" "BBDC3"
[10] "BBDC3" "BBDC3" "BBDC3"
[1] 736.67 764.14 768.63 776.47 59.40 59.80 59.20 59.28 29.81 30.82
[11] 30.38 30.20
[1] 736.67 764.14 768.63 776.47 59.40 59.80 59.20 59.28 29.81 30.82
# A tibble: 10 × 2
ticker ref_date
<chr> <date>
1 ABEV3 2010-01-01
2 ABEV3 2010-01-04
3 ABEV3 2010-01-05
4 ABEV3 2010-01-06
5 BBAS3 2010-01-01
6 BBAS3 2010-01-04
7 BBAS3 2010-01-05
8 BBAS3 2010-01-06
9 BBDC3 2010-01-01
10 BBDC3 2010-01-04
Atenção!
Ao usar notação de matriz ([row, column]) em um dataframe, o resultado é sempre outro dataframe.
O operador de pipeline é usado com os símbolos
|>(nativo com R > 4.1) e%>%(pacotemagrittr) e permite que dataframes sejam criados em etapas consecutivas
Imagine o seguinte código, onde a ideia é repassar um dataframe entre diferentes e consecutivas funções:
Uma maneira equivalente e mais elegante:
Rows: 10
Columns: 5
$ x <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
$ y <dbl> 0.33239467, 0.65087047, 0.25801678, 0.47854525, 0.76631067, 0.084…
$ col1 <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
$ col2 <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
$ col3 <dbl> 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
dataframePara criar novas colunas em um dataframe, basta utilizar a função dplyr::mutate
library(dplyr)
my_df <- yfR::yf_get(
tickers = c('ABEV3.SA', 'PETR4.SA'),
first_date = '2023-01-01',
last_date = '2023-01-15'
)
# add columns with mutate
my_df <- my_df |>
group_by(ticker) |>
mutate(ret = price_adjusted / dplyr::lag(price_adjusted) - 1) |>
ungroup() |>
mutate(my_seq1 = 1:nrow(my_df),
my_seq2 = my_seq1 + 9) |>
glimpse()Rows: 20
Columns: 14
$ ticker <chr> "ABEV3.SA", "ABEV3.SA", "ABEV3.SA", "ABEV3.SA",…
$ ref_date <date> 2023-01-02, 2023-01-03, 2023-01-04, 2023-01-05…
$ price_open <dbl> 14.40, 14.16, 14.28, 14.27, 14.30, 14.29, 14.26…
$ price_high <dbl> 14.45, 14.39, 14.47, 14.41, 14.36, 14.47, 14.60…
$ price_low <dbl> 14.02, 14.11, 14.08, 14.14, 14.16, 14.27, 14.25…
$ price_close <dbl> 14.19, 14.17, 14.25, 14.29, 14.32, 14.40, 14.54…
$ volume <dbl> 14995900, 36363800, 23791800, 31031500, 2088980…
$ price_adjusted <dbl> 11.85739, 11.84068, 11.90753, 11.94095, 11.9660…
$ ret_adjusted_prices <dbl> NA, -0.001409432, 0.005645766, 0.002806915, 0.0…
$ ret_closing_prices <dbl> NA, -0.001409408, 0.005645725, 0.002807015, 0.0…
$ cumret_adjusted_prices <dbl> 1.0000000, 0.9985906, 1.0042284, 1.0070472, 1.0…
$ ret <dbl> NA, -0.001409432, 0.005645766, 0.002806915, 0.0…
$ my_seq1 <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, …
$ my_seq2 <dbl> 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,…
A maneira mais tradicional, e comumente encontrada em código, para criar novas colunas é utilizar o símbolo $:
Rows: 20
Columns: 15
$ ticker <chr> "ABEV3.SA", "ABEV3.SA", "ABEV3.SA", "ABEV3.SA",…
$ ref_date <date> 2023-01-02, 2023-01-03, 2023-01-04, 2023-01-05…
$ price_open <dbl> 14.40, 14.16, 14.28, 14.27, 14.30, 14.29, 14.26…
$ price_high <dbl> 14.45, 14.39, 14.47, 14.41, 14.36, 14.47, 14.60…
$ price_low <dbl> 14.02, 14.11, 14.08, 14.14, 14.16, 14.27, 14.25…
$ price_close <dbl> 14.19, 14.17, 14.25, 14.29, 14.32, 14.40, 14.54…
$ volume <dbl> 14995900, 36363800, 23791800, 31031500, 2088980…
$ price_adjusted <dbl> 11.85739, 11.84068, 11.90753, 11.94095, 11.9660…
$ ret_adjusted_prices <dbl> NA, -0.001409432, 0.005645766, 0.002806915, 0.0…
$ ret_closing_prices <dbl> NA, -0.001409408, 0.005645725, 0.002807015, 0.0…
$ cumret_adjusted_prices <dbl> 1.0000000, 0.9985906, 1.0042284, 1.0070472, 1.0…
$ ret <dbl> NA, -0.001409432, 0.005645766, 0.002806915, 0.0…
$ my_seq1 <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, …
$ my_seq2 <dbl> 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,…
$ my_seq3 <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, …
Para remover colunas de um dataframe, basta usar dplyr::select com operador negativo para o nome das colunas indesejadas:
Rows: 20
Columns: 12
$ ticker <chr> "ABEV3.SA", "ABEV3.SA", "ABEV3.SA", "ABEV3.SA",…
$ ref_date <date> 2023-01-02, 2023-01-03, 2023-01-04, 2023-01-05…
$ price_open <dbl> 14.40, 14.16, 14.28, 14.27, 14.30, 14.29, 14.26…
$ price_high <dbl> 14.45, 14.39, 14.47, 14.41, 14.36, 14.47, 14.60…
$ price_low <dbl> 14.02, 14.11, 14.08, 14.14, 14.16, 14.27, 14.25…
$ price_close <dbl> 14.19, 14.17, 14.25, 14.29, 14.32, 14.40, 14.54…
$ volume <dbl> 14995900, 36363800, 23791800, 31031500, 2088980…
$ price_adjusted <dbl> 11.85739, 11.84068, 11.90753, 11.94095, 11.9660…
$ ret_adjusted_prices <dbl> NA, -0.001409432, 0.005645766, 0.002806915, 0.0…
$ ret_closing_prices <dbl> NA, -0.001409408, 0.005645725, 0.002807015, 0.0…
$ cumret_adjusted_prices <dbl> 1.0000000, 0.9985906, 1.0042284, 1.0070472, 1.0…
$ ret <dbl> NA, -0.001409432, 0.005645766, 0.002806915, 0.0…
No uso de funções nativas do R, a maneira tradicional de remover colunas é alocar o valor nulo (NULL):
Rows: 20
Columns: 13
$ ticker <chr> "ABEV3.SA", "ABEV3.SA", "ABEV3.SA", "ABEV3.SA",…
$ price_open <dbl> 14.40, 14.16, 14.28, 14.27, 14.30, 14.29, 14.26…
$ price_high <dbl> 14.45, 14.39, 14.47, 14.41, 14.36, 14.47, 14.60…
$ price_low <dbl> 14.02, 14.11, 14.08, 14.14, 14.16, 14.27, 14.25…
$ price_close <dbl> 14.19, 14.17, 14.25, 14.29, 14.32, 14.40, 14.54…
$ volume <dbl> 14995900, 36363800, 23791800, 31031500, 2088980…
$ ret_adjusted_prices <dbl> NA, -0.001409432, 0.005645766, 0.002806915, 0.0…
$ ret_closing_prices <dbl> NA, -0.001409408, 0.005645725, 0.002807015, 0.0…
$ cumret_adjusted_prices <dbl> 1.0000000, 0.9985906, 1.0042284, 1.0070472, 1.0…
$ ret <dbl> NA, -0.001409432, 0.005645766, 0.002806915, 0.0…
$ my_seq1 <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, …
$ my_seq2 <dbl> 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,…
$ my_seq3 <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, …
dataframedplyr::filter():Rows: 10
Columns: 15
$ ticker <chr> "ABEV3.SA", "ABEV3.SA", "ABEV3.SA", "ABEV3.SA",…
$ ref_date <date> 2023-01-02, 2023-01-03, 2023-01-04, 2023-01-05…
$ price_open <dbl> 14.40, 14.16, 14.28, 14.27, 14.30, 14.29, 14.26…
$ price_high <dbl> 14.45, 14.39, 14.47, 14.41, 14.36, 14.47, 14.60…
$ price_low <dbl> 14.02, 14.11, 14.08, 14.14, 14.16, 14.27, 14.25…
$ price_close <dbl> 14.19, 14.17, 14.25, 14.29, 14.32, 14.40, 14.54…
$ volume <dbl> 14995900, 36363800, 23791800, 31031500, 2088980…
$ price_adjusted <dbl> 11.85739, 11.84068, 11.90753, 11.94095, 11.9660…
$ ret_adjusted_prices <dbl> NA, -0.001409432, 0.005645766, 0.002806915, 0.0…
$ ret_closing_prices <dbl> NA, -0.001409408, 0.005645725, 0.002807015, 0.0…
$ cumret_adjusted_prices <dbl> 1.0000000, 0.9985906, 1.0042284, 1.0070472, 1.0…
$ ret <dbl> NA, -0.001409432, 0.005645766, 0.002806915, 0.0…
$ my_seq1 <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
$ my_seq2 <dbl> 10, 11, 12, 13, 14, 15, 16, 17, 18, 19
$ my_seq3 <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
A função também aceita mais de uma condição. Veja a seguir onde filtramos os dados para 'ABEV3.SA' em datas posteriores ou iguais a '2023-01-10':
Rows: 4
Columns: 15
$ ticker <chr> "ABEV3.SA", "ABEV3.SA", "ABEV3.SA", "ABEV3.SA"
$ ref_date <date> 2023-01-10, 2023-01-11, 2023-01-12, 2023-01-13
$ price_open <dbl> 14.26, 14.51, 13.80, 14.00
$ price_high <dbl> 14.60, 14.79, 14.17, 14.05
$ price_low <dbl> 14.25, 13.95, 13.66, 13.77
$ price_close <dbl> 14.54, 14.29, 14.10, 13.88
$ volume <dbl> 35535000, 74419600, 69959500, 44291300
$ price_adjusted <dbl> 12.14986, 11.94095, 11.78219, 11.59835
$ ret_adjusted_prices <dbl> 0.009722304, -0.017194124, -0.013295907, -0.015…
$ ret_closing_prices <dbl> 0.009722246, -0.017193948, -0.013295982, -0.01…
$ cumret_adjusted_prices <dbl> 1.0246654, 1.0070472, 0.9936576, 0.9781537
$ ret <dbl> 0.009722304, -0.017194124, -0.013295907, -0.015…
$ my_seq1 <int> 7, 8, 9, 10
$ my_seq2 <dbl> 16, 17, 18, 19
$ my_seq3 <int> 7, 8, 9, 10
dataframeNo tidyverse, a forma de ordenar dataframes é pelo uso da função arrange. No caso de ordenamento decrescente, encapsulamos o nome das colunas com desc:
# A tibble: 3 × 3
col1 col2 col3
<dbl> <dbl> <chr>
1 1 1 b
2 2 3 c
3 4 1 a
# A tibble: 3 × 3
col1 col2 col3
<dbl> <dbl> <chr>
1 4 1 a
2 2 3 c
3 1 1 b
dataframesdplyr::bind_rows()dplyr::bind_cols()dplyr::inner_join, dplyr::left_join, dplyr::right_join, dplyr::full_joindplyr::bind_rows()Rows: 10
Columns: 3
$ col1 <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
$ col2 <chr> "a", "a", "a", "a", "a", "b", "b", "b", "b", "b"
$ col3 <chr> NA, NA, NA, NA, NA, "c", "c", "c", "c", "c"
dplyr::bind_cols()Rows: 5
Columns: 4
$ col1 <int> 1, 2, 3, 4, 5
$ col2 <chr> "a", "a", "a", "a", "a"
$ col3 <int> 6, 7, 8, 9, 10
$ col4 <chr> "b", "b", "b", "b", "b"
joinleft_join()right_join()inner_join()dplyr::inner_join()Rows: 7
Columns: 3
$ date <date> 2016-01-05, 2016-01-06, 2016-01-07, 2016-01-08, 2016-01-09, 2016…
$ x <int> 5, 6, 7, 8, 9, 10, 11
$ y <dbl> 20, 21, 22, 23, 24, 25, 26
dplyr::left_join()# A tibble: 11 × 3
date x y
<date> <int> <dbl>
1 2016-01-01 1 NA
2 2016-01-02 2 NA
3 2016-01-03 3 NA
4 2016-01-04 4 NA
5 2016-01-05 5 20
6 2016-01-06 6 21
7 2016-01-07 7 22
8 2016-01-08 8 23
# ℹ 3 more rows
Uma lista (
list) é uma classe de objeto extremamente flexível. Ao contrário de vetores atômicos, a lista não apresenta restrição alguma em relação aos tipos de elementos nela contidos.
Uma lista pode ser criada através do comando base::list, seguido por seus elementos separados por vírgula:
[[1]]
[1] 1 2 3
[[2]]
[1] "a" "b"
[[3]]
[1] A B C
Levels: A B C
[[4]]
# A tibble: 5 × 1
col1
<int>
1 1
2 2
3 3
4 4
5 5
List of 4
$ : num [1:3] 1 2 3
$ : chr [1:2] "a" "b"
$ : Factor w/ 3 levels "A","B","C": 1 2 3
$ : tibble [5 × 1] (S3: tbl_df/tbl/data.frame)
..$ col1: int [1:5] 1 2 3 4 5
Também podemos nomear os elementos:
List of 3
$ ticker : chr "TICK4"
$ market : chr "Bovespa"
$ df_prices: tibble [4 × 2] (S3: tbl_df/tbl/data.frame)
..$ P : num [1:4] 1 1.5 2 2.3
..$ ref_date: Date[1:4], format: "2026-09-10" "2026-09-11" ...
Os elementos de uma lista podem ser acessados através do uso de duplo colchete ([[ ]]) ou $, tal como em:
Para adicionar ou substituir, basta definir um novo objeto na posição desejada da lista:
Para remover elementos de uma lista, basta definir o elemento para o símbolo reservado NULL (nulo):
Toda lista pode ser processada de forma programática através de funções específicas.
Por exemplo, imagine uma lista com vetores numéricos de diferentes tamanhos, tal como a seguir:
Caso quiséssemos calcular a média de cada elemento de my_l_num e apresentar o resultado na tela como um vetor, poderíamos fazer isso através de um procedimento simples, processando cada elemento individualmente:
[1] 2.0 25.5 0.0
O código anterior funciona, porém não é recomendado devido à sua falta de escalabilidade.
Uma maneira mais fácil, elegante e inteligente seria utilizar a função sapply (Base R) ou purrr::map_dbl (Tidyverse):
Uma matriz é uma representação bidimensional de diversos valores, arranjados em linhas e colunas. O uso de matrizes é uma poderosa maneira de representar dados numéricos em duas dimensões e, em certos casos, funções matriciais podem simplificar operações matemáticas complexas.
Um claro exemplo do uso de matrizes em Finanças seria a representação dos preços de diferentes ações ao longo do tempo.
| Data | ABEV3 | BBAS3 | BBDC3 |
|---|---|---|---|
| 2010-01-01 | 736.67 | 59.4 | 29.81 |
| 2010-01-04 | 764.14 | 59.8 | 30.82 |
| 2010-01-05 | 768.63 | 59.2 | 30.38 |
| 2010-01-06 | 776.47 | 59.28 | 30.20 |
A matriz anterior poderia ser criada da seguinte forma no R:
# create matrix
data <- c(736.67, 764.14, 768.63, 776.47,
59.4, 59.8, 59.2, 59.28,
29.81, 30.82, 30.38, 30.20)
my_mat <- matrix(data, nrow = 4, ncol = 3)
# set names of cols and rows
colnames(my_mat) <- c('ABEV3', 'BBAS3', 'BBDC3')
rownames(my_mat) <- c('2010-01-01', '2010-01-04',
'2010-01-05', '2010-01-06')
print(my_mat) ABEV3 BBAS3 BBDC3
2010-01-01 736.67 59.40 29.81
2010-01-04 764.14 59.80 30.82
2010-01-05 768.63 59.20 30.38
2010-01-06 776.47 59.28 30.20
[i,j], onde i representa a linha e j a coluna. Veja o exemplo a seguir: [,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
[1] 4
O uso de testes lógicos para selecionar valores de matrizes também é possível. Veja a seguir:
Crie um dataframe chamado my_df com uma coluna chamada x contendo uma sequência de 1 a 100 e outra coluna chamada y com o valor da coluna x adicionada de 5. Usando código, qual a quantidade de valores em x maiores que 10 e menores que 25?
Use a função dplyr::mutate para criar uma nova coluna em my_df chamada cumsum_x, contendo a soma cumulativa de x (função base::cumsum()). Desta nova coluna, quantos valores são maiores que 50?
Com a função dplyr::filter(), filtre o dataframe my_df para manter apenas as linhas onde o valor da coluna x é maior que 25.
Utilize o pacote yfR para baixar dados da ação da META/Facebook (META) desde a data '2010-01-01' até hoje. Filtre os dados para manter apenas dados onde o dia da semana era segunda-feira.
Importe os dados disponíveis no arquivo CH11_grunfeld.csv, disponível no arquivo com os dados do livro. Utilize funções dplyr::glimpse, summary e skimr::skim para conhecer os dados importados.
Crie um objeto do tipo lista com três dataframes em seu conteúdo, df1, df2 e df3. O conteúdo e tamanho dos dataframes é livre. Utilize a função sapply para descobrir o número de linhas e colunas em cada dataframe.
Usando o pacote yfR, baixe os dados da Petrobras (PETR4.SA) e do índice Ibovespa (^BVSP) em dois dataframes diferentes (duas chamadas da função yfR::yf_get). Empilhe os dados das duas ações com o comando dplyr::bind_rows.
Usando os mesmos dados do exercício anterior, crie uma nova coluna na tabela da Petrobras com os retornos do índice Ibovespa. A tabela resultante deve ser como a apresentada a seguir:
| ref_date | ret_petr4 | ret_ibov |
|---|---|---|
| 2026-09-11 | 100.7773 | 100.2455 |
| 2026-09-12 | 101.7379 | 100.3888 |
| 2026-09-13 | 102.1726 | 100.6284 |
| 2026-09-14 | 102.8851 | 100.6874 |
| 2026-09-15 | 103.2851 | 101.3296 |
| 2026-09-16 | 103.6105 | 102.2059 |
| 2026-09-17 | 104.3675 | 102.9848 |
| 2026-09-18 | 104.5702 | 103.7821 |
| 2026-09-19 | 105.2814 | 104.2374 |
| 2026-09-20 | 105.4031 | 104.6475 |
Note que você precisará:
ADFER - UFRGS