Análise de Dados e Documentos Dinâmicos

Tópico IV - Manipulação de Dados II

Antonio Vinícius Barbosa

2024-04-17

Junção de Dados

  • Nesta parte do curso, veremos algumas funções úteis para realizar a junção (ou joins ou merge) de bases de dados no R.
  • O join de bases de dados surge da necessidade de juntar informações de fontes distintas em uma única base de dados.
  • Join é um conceito bastante comum para quem já trabalha com bancos de dados (principalmente com SQL).

Junção de Dados

Para realizar joins, utilizamos o conceito de chaves, variáveis que identificam cada observação de maneira única. Alguns exemplos:

  • O CPF de um indivíduo
  • O número de matrícula de uma aluno
  • O CNPJ de um estabelecimento
  • O código IBGE de um município
  • A sigla de um país…

Em muitas situações, no entanto, as chaves de identificação das unidades de observação estão restritas a bases de dados não públicas. Além disso, nos últimos anos foi necessária a adequação à Lei Geral de Proteção de dados (LGPD).

Junção de Dados

Para entender o conceito de joins, utilizaremos a representação gráfica baseada no livro R for Data Science. Considere dois bancos de dados, com a chave dos indivíduos e o valor de uma variável

Junção de Dados

# Base de dados 
x <- tibble(
  key = c(1, 2, 3),
  val_x = c("x1", "x2", "x3")
)

y <- tibble(
  key = c(1, 2, 4),
  val_y = c("y1", "y2", "y3")
)

De forma geral

O pacote dplyr possui funções que possibilitam realizar o joins (ou merge) de duas bases de dados. Podemos utilizar o diagrama de Venn para ter uma visão geral dos diferentes tipos:



Joins

As principais funções utilizadas são:

  • inner_join()
  • left_join()
  • right_join()
  • full_join()

Usando o inner_join()

As principais funções utilizadas são:

  • inner_join(): retorna apenas as linhas com correspondências nas duas bases.
  • left_join()
  • right_join()
  • full_join()

Usando o inner_join()

O resultado do inner_join() é uma nova base que contem as chaves comuns nas duas bases e os valores da variáveis na base de dados x e na base de dados y

# Juncao de bases 
inner_join(x, y, by = "key")
## # A tibble: 2 × 3
##     key val_x val_y
##   <dbl> <chr> <chr>
## 1     1 x1    y1   
## 2     2 x2    y2

Usando o inner_join()

Para um exemplo mais concreto, utilizaremos dois bancos de dados: um com informações sobre os funcionários de uma empresa e outro com a remuneração média para cada cargo.

# Informacoes sobre homicidios por genero
homicidios <- tibble(
  codigo_ibge = c("3550308", "3304557", "3106200", "2927408", "5300108", 
                  "4106902", "2611606", "2304400", "1302603", "4314902"),
  municipio = c("São Paulo", "Rio de Janeiro", "Belo Horizonte", "Salvador",
                "Brasília", "Curitiba", "Recife", "Fortaleza", "Manaus", 
                "Porto Alegre"),
  homicidios_homem = c(200, 150, 80, 120, 90, 60, 50, 70, 40, 55),
  homicidios_mulher = c(40, 30, 20, 35, 25, 15, 10, 20, 12, 18)
)

# Criando tabela com informações sobre a população dos municípios
populacao <- tibble(
  codigo_ibge = c("3550308", "3304557", "3106200", "2927408", "5300108", 
                  "4106902", "2611606", "2304400", "1302603", "4314902"),
  populacao = c(12000000, 6500000, 2500000, 2900000, 3100000, 1900000, 
                1600000, 2700000, 2200000, 1500000)
)

Usando o inner_join()

# Dados de homicidios
homicidios
## # A tibble: 10 × 4
##    codigo_ibge municipio      homicidios_homem homicidios_mulher
##    <chr>       <chr>                     <dbl>             <dbl>
##  1 3550308     São Paulo                   200                40
##  2 3304557     Rio de Janeiro              150                30
##  3 3106200     Belo Horizonte               80                20
##  4 2927408     Salvador                    120                35
##  5 5300108     Brasília                     90                25
##  6 4106902     Curitiba                     60                15
##  7 2611606     Recife                       50                10
##  8 2304400     Fortaleza                    70                20
##  9 1302603     Manaus                       40                12
## 10 4314902     Porto Alegre                 55                18
# Dados de populacao
populacao
## # A tibble: 10 × 2
##    codigo_ibge populacao
##    <chr>           <dbl>
##  1 3550308      12000000
##  2 3304557       6500000
##  3 3106200       2500000
##  4 2927408       2900000
##  5 5300108       3100000
##  6 4106902       1900000
##  7 2611606       1600000
##  8 2304400       2700000
##  9 1302603       2200000
## 10 4314902       1500000

Usando o inner_join()

O inner_join() cria uma base retornando apenas as ocorrências (linhas) que possuem chaves iguais nos dois conjuntos:

inner_join(homicidios, populacao, by = "codigo_ibge")
## # A tibble: 10 × 5
##    codigo_ibge municipio      homicidios_homem homicidios_mulher populacao
##    <chr>       <chr>                     <dbl>             <dbl>     <dbl>
##  1 3550308     São Paulo                   200                40  12000000
##  2 3304557     Rio de Janeiro              150                30   6500000
##  3 3106200     Belo Horizonte               80                20   2500000
##  4 2927408     Salvador                    120                35   2900000
##  5 5300108     Brasília                     90                25   3100000
##  6 4106902     Curitiba                     60                15   1900000
##  7 2611606     Recife                       50                10   1600000
##  8 2304400     Fortaleza                    70                20   2700000
##  9 1302603     Manaus                       40                12   2200000
## 10 4314902     Porto Alegre                 55                18   1500000

Quizz #1

Suponha que o nome das variáveis utilizadas para fazer o join são distintas, conforme o exemplo a seguir. Como realizar o inner_join() neste caso?

# Data x
data_x <- tibble(
  id = c(1, 2, 3, 4),
  valor_x = c(12, 54, 7, 42)
)

# Data y
data_y <- tibble(
  codigo = c(1, 3, 4, 5),
  valor_y = c(23, 56, 23, 11)
)

Usando o inner_join()

  • Um ponto importante é o fato do inner_join desconsiderar do resultado as informações que não tiveram matching.
  • Isto pode ser uma propriedade não desejada caso queiramos manter todas as informações em uma análise de dados, dada a perda de informações

Outer joins

Como vimos, o inner_join() não leva em consideração as linhas onde as chaves não coincidem. Se quisermos manter todas as informações, utilizamos o conceito de outer joins. Existem três tipos básicos:

  • left_join()
  • right_join()
  • full_join()

Outer joins

Para os exemplos a seguir, considere as seguintes bases de dados:

# Base de dados pacientes
pacientes <- tibble(
  id_paciente = 1:9,
  nome = c("A.A.M", "S.S.G.F", "T.I.A", "L.O.S.M", "Y.Q.W", 
           "F.A", "T.B.N", "J.J.L", "M.S.S"),
  exame_a = c(3.8, 3.8, 3.9, 4.0, 4.4, 3.8, 3.7, 3.6, 4.0),
  exame_b = c(89.9, 89.9, 99.8, 99.9, 100.0, 89.9, 
              109.9, 109.9, 110.0),
  exame_c = c(0, 1, 1, 0, 1, 1, 0, 0, 1)
)

# Base de dados tratamento
tratamento <- tibble(
  id_paciente = c(1, 4, 5, 7, 8, 11, 15, 25),
  medicamento = c("A", "B", "A", "B", "A", "A", "B", "B")
)

Outer joins

# Visualizando pacientes
pacientes
## # A tibble: 9 × 5
##   id_paciente nome    exame_a exame_b exame_c
##         <int> <chr>     <dbl>   <dbl>   <dbl>
## 1           1 A.A.M       3.8    89.9       0
## 2           2 S.S.G.F     3.8    89.9       1
## 3           3 T.I.A       3.9    99.8       1
## 4           4 L.O.S.M     4      99.9       0
## 5           5 Y.Q.W       4.4   100         1
## 6           6 F.A         3.8    89.9       1
## 7           7 T.B.N       3.7   110.        0
## 8           8 J.J.L       3.6   110.        0
## 9           9 M.S.S       4     110         1
# Visualizando tratamento
tratamento
## # A tibble: 8 × 2
##   id_paciente medicamento
##         <dbl> <chr>      
## 1           1 A          
## 2           4 B          
## 3           5 A          
## 4           7 B          
## 5           8 A          
## 6          11 A          
## 7          15 B          
## 8          25 B

Usando o left_join()

As principais funções utilizadas são:

  • inner_join()
  • left_join(): mantém todas as observações do banco x (o banco do lado esquerdo)
  • right_join()
  • full_join()

Usando o left_join()

A função left_join() preserva todas as observações do lado esquerdo (x) e remove as informações do lado direito (y) que não possuem correspondência.

  • O resultado é uma base com informações dos indivíduos 1, 2, e 3 .
  • O indivíduo 4 foi excluído por não ter correspondência em x.

Usando o left_join()

Para preservar todos os pacientes e desprezar os registros de tratamento que não correspondem a pacientes hospitalizados, fazemos:

# Left join do dplyr
left_join(pacientes, tratamento, join_by(id_paciente))
## # A tibble: 9 × 6
##   id_paciente nome    exame_a exame_b exame_c medicamento
##         <dbl> <chr>     <dbl>   <dbl>   <dbl> <chr>      
## 1           1 A.A.M       3.8    89.9       0 A          
## 2           2 S.S.G.F     3.8    89.9       1 <NA>       
## 3           3 T.I.A       3.9    99.8       1 <NA>       
## 4           4 L.O.S.M     4      99.9       0 B          
## 5           5 Y.Q.W       4.4   100         1 A          
## 6           6 F.A         3.8    89.9       1 <NA>       
## 7           7 T.B.N       3.7   110.        0 B          
## 8           8 J.J.L       3.6   110.        0 A          
## 9           9 M.S.S       4     110         1 <NA>

Usando o right_join()

As principais funções são:

  • inner_join()
  • left_join()
  • right_join(): mantém todas as observações do banco y (o banco do lado direito)
  • full_join()

Usando o right_join()

O comando right_join() preserva todas as observações do lado direito e remove as informações do lado esquerdo que não possuem correspondência.

  • Neste caso, o resultado é uma base com informações dos pacientes 1, 2, e 4. O indivíduo 3 foi excluido por não ter não ter correspondência em y.

Usando o right_join()

Para preservar todos as linhas do conjunto da direita (tratamento) e desprezar os pacientes sem correspondência de chave, fazemos:

# Right join do dplyr
right_join(pacientes, tratamento, join_by(id_paciente))
## # A tibble: 8 × 6
##   id_paciente nome    exame_a exame_b exame_c medicamento
##         <dbl> <chr>     <dbl>   <dbl>   <dbl> <chr>      
## 1           1 A.A.M       3.8    89.9       0 A          
## 2           4 L.O.S.M     4      99.9       0 B          
## 3           5 Y.Q.W       4.4   100         1 A          
## 4           7 T.B.N       3.7   110.        0 B          
## 5           8 J.J.L       3.6   110.        0 A          
## 6          11 <NA>       NA      NA        NA A          
## 7          15 <NA>       NA      NA        NA B          
## 8          25 <NA>       NA      NA        NA B

Usando o full_join()

As principais funções são:

  • inner_join()
  • left_join()
  • right_join()
  • full_join(): mantem todas as observações dos bancos x e y

Usando o full_join()

O comando full_join() preserva todas as observações de ambos os bancos

  • O resultado é uma base com informações completas, com as correspondências incompletas representadas por NA.

Usando o full_join()

Para preservar todos os registros de ambos os conjuntos de dados, fazemos:

# Full join do dplyr
full_join(pacientes, tratamento, join_by(id_paciente))
## # A tibble: 12 × 6
##    id_paciente nome    exame_a exame_b exame_c medicamento
##          <dbl> <chr>     <dbl>   <dbl>   <dbl> <chr>      
##  1           1 A.A.M       3.8    89.9       0 A          
##  2           2 S.S.G.F     3.8    89.9       1 <NA>       
##  3           3 T.I.A       3.9    99.8       1 <NA>       
##  4           4 L.O.S.M     4      99.9       0 B          
##  5           5 Y.Q.W       4.4   100         1 A          
##  6           6 F.A         3.8    89.9       1 <NA>       
##  7           7 T.B.N       3.7   110.        0 B          
##  8           8 J.J.L       3.6   110.        0 A          
##  9           9 M.S.S       4     110         1 <NA>       
## 10          11 <NA>       NA      NA        NA A          
## 11          15 <NA>       NA      NA        NA B          
## 12          25 <NA>       NA      NA        NA B

Quizz #2

# Cadastro de clientes
clientes <- tibble(
  id_cliente = c(1, 2, 3, 4, 5),
  nome_cliente = c("João", "Maria", "Pedro", "Ana", "Luiza"),
  idade_cliente = c(30, 25, 40, 35, 28),
  sexo = c("M", "F", "M", "F", "F")
)

# Historico de compras
compras <- tibble(
  id_cliente = c(1, 2, 3, 4, 1, 2, 3),
  produto = c("Celular", "Notebook", "Tablet", "Smartwatch", 
              "Fone de Ouvido", "Teclado", "Mouse"),
  valor_compra = c(1500, 2500, 800, 300, 100, 80, 50)
)
  • Encontre os gastos totais de cada cliente da loja.
  • Encontre os gastos médio por sexo.

Formatação de dados

O pacote tidyr

O pacote tidyr dispõe de funções bastante úteis para organizar os dados no formato necessário para a análise.

Pivoting

Pivoting

Existem dois tipos de formatação dos dados:

Pivoting

As principais funções para transformar os dados para formato long ou wide são:

  • pivot_longer(): empilha o banco de dados, deixando no formato longo (long).
  • pivot_wider(): transforma o banco para um formato expandido (wide).

A função pivot_longer()

  • pivot_longer(): empilha o banco de dados, deixando no formato longo.

A função pivot_longer()

Neste exemplo, vamos criar um tibble:

# Criar dados
dados_uf <- tibble(
  uf = c("RJ", "SP", "PB"),
  `2017` = c(23, 45, 19),
  `2018` = c(20, 38, 17),
  `2019` = c(28, 36, 20)
)

dados_uf
## # A tibble: 3 × 4
##   uf    `2017` `2018` `2019`
##   <chr>  <dbl>  <dbl>  <dbl>
## 1 RJ        23     20     28
## 2 SP        45     38     36
## 3 PB        19     17     20

A função pivot_longer()

Utilizando a função pivot_longer()

dados_uf_long <- dados_uf |>  
  pivot_longer(
    cols = `2017`:`2019`,
    names_to = "ano",
    values_to = "valor"
    )

dados_uf_long
## # A tibble: 9 × 3
##   uf    ano   valor
##   <chr> <chr> <dbl>
## 1 RJ    2017     23
## 2 RJ    2018     20
## 3 RJ    2019     28
## 4 SP    2017     45
## 5 SP    2018     38
## 6 SP    2019     36
## 7 PB    2017     19
## 8 PB    2018     17
## 9 PB    2019     20

Tal formato é bastante utilizado para análises de unidades ao longo do tempo (por exemplo, em análises de dados de séries temporais ou dados em painel)

Quizz #1

Altere para long o formato do banco com informações do peso (em gramas) de recém nascidos, transformando apenas as variáveis contendo informações do peso, ordenados em ordem alfabética dos nomes:

peso_recem_nascido <- tibble(
  nome = c("João", "Maria", "José", "Ana"),
  sobrenome = c("Oliveira", "Duarte", "Silveira", "Cavalcante"),
  sexo = c("M", "F", "M", "F"),
  mes_0 = c(4300, 5240, 5180, 5450),
  mes_1 = c(5300, NA, 6607, 6900),
  mes_2 = c(4560, 6301, NA, 8765),
  mes_3 = c(5003, NA, 6015, 6399)
)

peso_recem_nascido
## # A tibble: 4 × 7
##   nome  sobrenome  sexo  mes_0 mes_1 mes_2 mes_3
##   <chr> <chr>      <chr> <dbl> <dbl> <dbl> <dbl>
## 1 João  Oliveira   M      4300  5300  4560  5003
## 2 Maria Duarte     F      5240    NA  6301    NA
## 3 José  Silveira   M      5180  6607    NA  6015
## 4 Ana   Cavalcante F      5450  6900  8765  6399
05:00

Quizz #2

Neste exercício, retomaremos ao exemplo dos dados históricos do Índice Bovespa (Ibovespa) disponíveis no site da B3 http://www.b3.com.br/pt_br/market-data-e-indices/indices/indices-amplos/indice-ibovespa-ibovespa-estatisticas-historicas.htm

  1. Baixe os dados referente ao segundo semestre de 2022
  2. Leia os dados corretamente, transformando em um formato tidy.
  3. Transforme os dados para o formato long.
  4. [Desafio] Como você faria para colocar os dados em ordem cronológica crescente? (Ver documentação da função)
10:00

A função pivot_wider()

A função pivot_wider() transforma o banco para um formato expandido (wide)

A função pivot_wider()

Pra transformar do formato long para wide:

# Formato wide
dados_uf_long |> 
  pivot_wider(
    names_from = "ano",
    values_from = "valor",
    names_prefix =  "ano_"
  )
## # A tibble: 3 × 4
##   uf    ano_2017 ano_2018 ano_2019
##   <chr>    <dbl>    <dbl>    <dbl>
## 1 RJ          23       20       28
## 2 SP          45       38       36
## 3 PB          19       17       20

Quizz #3

  1. Utilize os dados population inseridos no pacote tidyr através de tidyr::population.
  2. Salve os dados em um objeto.
  3. Transforme para o formato wide.
  4. Utilize o argumento prefix par adicionar ano_ antes do nome de cada coluna pivoteada.
05:00