Dataframes e outros Objetos

Análise de Dados Financeiros e Econômicos com o R

Marcelo S. Perlin

EA-UFRGS

10/09/2026

As Classes de Armazenamento no R

Introdução

  • As classes básicas de objetos no R (números, texto, …) em vetores são difíceis de trabalhar com dados em larga escala (muitas observações, muitas colunas)
  • Classes de armazenamento facilitam a agregação de objetos de forma estruturada
  • dataframes e lists são os objetos mais usados no R

Introdução

dataframe ou tibble significa “estrutura ou organização de dados”. Grosso modo, um objeto da classe dataframe nada mais é do que uma tabela, com linhas e colunas.

  • principal objeto utilizado no trabalho com o R, sendo usado como tipo de entrada para diferentes funções
  • 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.
  • organiza os dados, forçando o pareamento de variáveis
  • altamente escalável para dados complexos

Criando dataframes

Exemplo simples

df <- tibble::tibble(
  x = 1:10,
  y = sample(letters, 10)
)

dplyr::glimpse(df)
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"

Exemplo menos simples

# 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

Inspecionando um dataframe

Atençã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:

  • Número de linhas e colunas
  • Nomes das colunas
    • sem caracteres latinos, espaços ou até mesmo caixa alta
    • preferencialmente em inglês
  • Classes das colunas
  • Existência de dados omissos (NA)
  • Verificar se dados fazem sentido

Função dplyr::glimpse()

library(dplyr)

# check content of my_df
glimpse(my_df)
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…

Função base::summary()

# check variation my_df
summary(my_df)
       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  

Função skimr::skim()

skimr::skim(my_df)
Data summary
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 ▇▁▁▁▃

Exemplo

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

Problemas

  • coluna Data em formato local (dd/mm/yyyy)
  • coluna id.candidato tem somente valor 1
  • coluna Nome do Candidato tem espaço no nome da coluna, e valores que não fazem sentido
  • coluna Profissão tem caractere especial e valor “casado”, o qual não faz sentido
  • coluna age está em inglês e apresenta valores negativos (ex: -5)
  • ninguém com menos de 10 anos pode estar casado!!!!

Acessando Elementos de um dataframe

  • use sempre nomes para acessar colunas (via posição é possível, mas não recomendado)
  • toda coluna de um dataframe vira um vetor atômico
  • todo dataframe possui notação matricial para elementos individuais ou blocos

Acessando colunas inteiras

Existem duas principais maneiras de acessar uma coluna de um dataframe via nome:

# isolate columns of df
my_ticker <- my_df$ticker
my_prices <- my_df[['price']]

# print contents
print(my_ticker)
 [1] "ABEV3" "ABEV3" "ABEV3" "ABEV3" "BBAS3" "BBAS3" "BBAS3" "BBAS3" "BBDC3"
[10] "BBDC3" "BBDC3" "BBDC3"
print(my_prices)
 [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

Acessando valores específicos

# first element
my_price <- my_df$price[1] 

print(my_price)
[1] 736.67
# first 10 elements
my_prices <- my_df$price[1:10] 

print(my_prices)
 [1] 736.67 764.14 768.63 776.47  59.40  59.80  59.20  59.28  29.81  30.82
# first 10 rows of first and second column (returns a tibble!)
my_prices <- my_df[1:10, 1:2] 

print(my_prices)
# 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.

Introdução

O operador de pipeline é usado com os símbolos |> (nativo com R > 4.1) e %>% (pacote magrittr) 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:

df1 <- fct1(df0)
df2 <- fct2(df1)
df3 <- fct3(df2)

Uma maneira equivalente e mais elegante:

my_tab <- my_df |>
  fct1() |>
  fct2() |>
  fct3()

Um exemplo prático

df <- tibble::tibble(
  x = 1:10,
  y = runif(10)
)

fct1 <- function(df_in) {
  df_in$col1 <- 1
  return(df_in)
}

fct2 <- function(df_in) {
  df_in$col2 <- 2
  return(df_in)
}

fct3 <- function(df_in) {
  df_in$col3 <- 3
  return(df_in)
}


df_3 <- df |>
  fct1() |>
  fct2() |>
  fct3()

dplyr::glimpse(df_3)
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

Modificando um dataframe

Para 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 $:

# add new column with base R
my_df$my_seq3 <- 1:nrow(my_df)

# check it
glimpse(my_df)
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, …

Removendo colunas

Para remover colunas de um dataframe, basta usar dplyr::select com operador negativo para o nome das colunas indesejadas:

# removing columns
my_df_temp <- my_df |>
  select(-my_seq1, -my_seq2, -my_seq3) |>
  glimpse()
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):

# set temp df
temp_df <- my_df

# remove cols
temp_df$price_adjusted <- NULL
temp_df$ref_date  <- NULL

# check it
glimpse(temp_df)
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, …

Filtrando linhas de um dataframe

  • selecione linhas de uma tabela com dplyr::filter():
library(dplyr)

# filter df for single stock
df_temp1 <- my_df |>
  filter(ticker == 'ABEV3.SA') |>
  glimpse()
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':

library(dplyr)
# filter df for single stock and date
my_df_temp <- my_df |>
  filter(ticker == 'ABEV3.SA',
         ref_date >= as.Date('2023-01-10')) |>
  glimpse()
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

Ordenando um dataframe

No tidyverse, a forma de ordenar dataframes é pelo uso da função arrange. No caso de ordenamento decrescente, encapsulamos o nome das colunas com desc:

library(dplyr)

# set df
my_df <- tibble(col1 = c(4,1,2),
                col2 = c(1,1,3),
                col3 = c('a','b','c'))

# sort ascending, by col1 and col2
my_df <- my_df |>
  arrange(col1, col2) |>
  print()
# A tibble: 3 × 3
   col1  col2 col3 
  <dbl> <dbl> <chr>
1     1     1 b    
2     2     3 c    
3     4     1 a    
# sort descending, col1 and col2
my_df <- my_df |>
  arrange(desc(col1), desc(col2)) |>
  print()
# A tibble: 3 × 3
   col1  col2 col3 
  <dbl> <dbl> <chr>
1     4     1 a    
2     2     3 c    
3     1     1 b    

Combinando e Agregando dataframes

  • podemos combinar tabelas por linhas (orientação vertical): dplyr::bind_rows()
  • podemos combinar tabelas por colunas (orientação horizontal): dplyr::bind_cols()
  • agregar tabelas de acordo com colunas: dplyr::inner_join, dplyr::left_join, dplyr::right_join, dplyr::full_join

Função dplyr::bind_rows()

Exemplo de uso

library(dplyr)

# set dfs
my_df_1 <- tibble(col1 = 1:5,
                  col2 = rep('a', 5))

my_df_2 <- tibble(col1 = 6:10,
                  col2 = rep('b', 5),
                  col3 = rep('c', 5))

# bind by row
my_df <- bind_rows(my_df_1, my_df_2) |>
  glimpse()
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"

Função dplyr::bind_cols()

Exemplo de uso

# set dfs
my_df_1 <- tibble(col1 = 1:5, col2 = rep('a', 5))
my_df_2 <- tibble(col3 = 6:10, col4 = rep('b', 5))

# bind by column
my_df <- bind_cols(my_df_1, my_df_2) |>
  glimpse()
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"

Funções da família join

left_join()

right_join()

inner_join()

Exemplo dplyr::inner_join()

# set df
my_df_1 <- tibble(date = as.Date('2016-01-01')+0:10,
                  x = 1:11)

my_df_2 <- tibble(date = as.Date('2016-01-05')+0:10,
                  y = seq(20,30, length.out = 11))

# aggregate tables
my_df <- inner_join(my_df_1, my_df_2)

glimpse(my_df)
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

Exemplo dplyr::left_join()

# left_join mantém todas as linhas da tabela à esquerda e preenche faltantes com NA
my_df_left <- left_join(my_df_1, my_df_2, by = "date")

print(my_df_left, n = 8)
# 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

Listas

Introdução

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.

  • um dos objetos mais utilizados no R
  • acomoda informações complexas de forma fácil

Criando Listas

Uma lista pode ser criada através do comando base::list, seguido por seus elementos separados por vírgula:

library(dplyr)

# create list
my_l <- list(c(1, 2, 3),
             c('a', 'b'),
             factor(c('A', 'B', 'C')),
             tibble(col1 = 1:5))

# use base::print
print(my_l)
[[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
# use dplyr::glimpse
glimpse(my_l)
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:

# set named list
my_named_l <- list(ticker = 'TICK4',
                   market = 'Bovespa',
                   df_prices = tibble(P = c(1,1.5,2,2.3),
                                      ref_date = Sys.Date()+0:3))

# check content
glimpse(my_named_l)
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" ...

Acessando os Elementos de uma Lista

Os elementos de uma lista podem ser acessados através do uso de duplo colchete ([[ ]]) ou $, tal como em:

# accessing elements from list
print(my_named_l[[2]]) # using position
[1] "Bovespa"
print(my_named_l[["df_prices"]]) # using name
# A tibble: 4 × 2
      P ref_date  
  <dbl> <date>    
1   1   2026-09-10
2   1.5 2026-09-11
3   2   2026-09-12
4   2.3 2026-09-13
print(my_named_l$ticker) # using $
[1] "TICK4"

Adicionando e Removendo Elementos de uma Lista

Para adicionar ou substituir, basta definir um novo objeto na posição desejada da lista:

# set list
my_l <- list(slot1 = 'a',
             slot2 = 1:10)

# add new elements to list
my_l$slot3 <- c(1:5)
my_l$slot4 <- rep("b", 15)

# print result
glimpse(my_l)
List of 4
 $ slot1: chr "a"
 $ slot2: int [1:10] 1 2 3 4 5 6 7 8 9 10
 $ slot3: int [1:5] 1 2 3 4 5
 $ slot4: chr [1:15] "b" "b" "b" "b" ...

Removendo elementos de uma lista

Para remover elementos de uma lista, basta definir o elemento para o símbolo reservado NULL (nulo):

# set list
my_l <- list(text = 'b', 
             num1 = 2, 
             num2 = 4)

# remove elements
my_l$num1 <- NULL
my_l$num2 <- NULL

glimpse(my_l)
List of 1
 $ text: chr "b"

Processando os Elementos de uma Lista

Toda lista pode ser processada de forma programática através de funções específicas.

  • processar elemento por elemento de uma lista

Por exemplo, imagine uma lista com vetores numéricos de diferentes tamanhos, tal como a seguir:

# set list
my_l_num <- list(c(1, 2, 3),
                 1:50,
                 seq(-5, 5, by = 0.5))

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:

# calculate mean of vectors
mean_1 <- mean(my_l_num[[1]])
mean_2 <- mean(my_l_num[[2]])
mean_3 <- mean(my_l_num[[3]])

# print it
print(c(mean_1, mean_2, mean_3))
[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):

# using base R
my_mean <- sapply(my_l_num, mean)
print(my_mean)
[1]  2.0 25.5  0.0
# using tidyverse (purrr)
purrr::map_dbl(my_l_num, mean)
[1]  2.0 25.5  0.0

Matrizes

Introdução

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

Selecionando Valores de uma Matriz

  • Os elementos de uma matriz podem ser acessados pela notação [i,j], onde i representa a linha e j a coluna. Veja o exemplo a seguir:
my_mat <- matrix(1:9, nrow = 3)
print(my_mat)
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9
print(my_mat[1,2])
[1] 4

O uso de testes lógicos para selecionar valores de matrizes também é possível. Veja a seguir:

my_mat <- matrix(1:9, nrow = 3)
print(my_mat >5)
      [,1]  [,2] [,3]
[1,] FALSE FALSE TRUE
[2,] FALSE FALSE TRUE
[3,] FALSE  TRUE TRUE

Tarefa final de aula

Tarefa 03 - Manipulação Básica

  1. 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?

  2. 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?

  3. 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.

Tarefa 03 - Dados Financeiros e Listas

  1. 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.

  2. 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.

  3. 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.

Tarefa 03 - Integração de Mercado

  1. 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.

  2. 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á:

  • renomear e selecionar colunas da tabela da Petrobras
  • renomear e selecionar colunas da tabela do Ibovespa
  • realizar o “merge” das tabelas usando as datas como referências

Referências