Transformando dados

Introdução

Primeiramente, precisamos carregar o pacote tidyverse e a base de dados que vamos utilizar. A base de dados é a tabela 4092 do SIDRA, que apresenta dados sobre “pessoas de 14 anos ou mais de idade por condição em relação à força de trabalho e condição de ocupação”1, e foi baixada previamente (em Importando dados).

Neste capítulo, vamos explorar as funções de transformação de dados do pacote dplyr, a partir da pergunta norteadora abaixo:

Considerando que a tabela 4092 apresenta dados sobre “pessoas de 14 anos ou mais de idade por condição em relação à força de trabalho e condição de ocupação”, qual é a taxa de desocupação de cada estado e região do Brasil ao longo do tempo?

library(dplyr)
dados_brutos <- readr::read_rds("dados/sidrar_4092_bruto.rds") 

Linhas, colunas e objetivo de análise

Uma pergunta que é sempre importante ter em mente ao analisar dados é: O que cada linha representa? Na estatística, esse é o conceito da unidade observacional.

O objeto dados_brutos apresenta uma linha para cada combinação das seguintes variáveis:

  • Trimestre (Código) / Trimestre

  • Unidade da Federação / Unidade da Federação (Código)

  • Variável / Variável (Código)

  • Condição em relação à força de trabalho e condição de ocupação e Condição em relação à força de trabalho e condição de ocupação (Código)

Podemos consultar os valores distintos possíveis no R, para garantir que estamos selecionando corretamente os valores de interesse.

As variáveis disponíveis na base de dados, e suas unidades de medida são:

dados_brutos |>
  distinct(`Variável`, `Unidade de Medida`)
1
Colunas que queremos buscar os valores distintos
                                                                                   Variável
1                                                       Pessoas de 14 anos ou mais de idade
2                             Coeficiente de variação - Pessoas de 14 anos ou mais de idade
3                           Distribuição percentual das pessoas de 14 anos ou mais de idade
4 Coeficiente de variação - Distribuição percentual das pessoas de 14 anos ou mais de idade
  Unidade de Medida
1       Mil pessoas
2                 %
3                 %
4                 %

Podemos observar, cada linha representa uma combinação de trimestre, unidade da federação e variável.

Outras perguntas relevantes ao analisar dados são:

  • Qual é a pergunta que eu quero responder com esses dados?
  • Quais são as variáveis que eu preciso para responder essa pergunta?

Padronizar nome das colunas

É uma boa prática padronizar o nome das colunas de um data frame. Assim evitamos problemas de codificação de caracteres (encoding), facilitamos a legibilidade do código e evitamos possíveis erros ao acessar as colunas.

O pacote janitor possui a função clean_names(), que padroniza os nomes das colunas de um data frame. Ele substitui espaços por underline (_), remove caracteres especiais, e transforma o texto em minúsculo, garantindo maior consistência ao lidar com os dados. Isso evita erros ao acessar colunas.

names(dados_brutos)
1
Checar o nome das colunas da base de dados
 [1] "Nível Territorial (Código)"                                             
 [2] "Nível Territorial"                                                      
 [3] "Unidade de Medida (Código)"                                             
 [4] "Unidade de Medida"                                                      
 [5] "Valor"                                                                  
 [6] "Unidade da Federação (Código)"                                          
 [7] "Unidade da Federação"                                                   
 [8] "Trimestre (Código)"                                                     
 [9] "Trimestre"                                                              
[10] "Variável (Código)"                                                      
[11] "Variável"                                                               
[12] "Condição em relação à força de trabalho e condição de ocupação (Código)"
[13] "Condição em relação à força de trabalho e condição de ocupação"         
dados_renomeados <- janitor::clean_names(dados_brutos)

names(dados_renomeados)
1
Limpar nomes das colunas da base de dados, e salvar em um novo objeto chamado dados_renomeados
2
Checar o nome das colunas da base de dados renomeada
 [1] "nivel_territorial_codigo"                                             
 [2] "nivel_territorial"                                                    
 [3] "unidade_de_medida_codigo"                                             
 [4] "unidade_de_medida"                                                    
 [5] "valor"                                                                
 [6] "unidade_da_federacao_codigo"                                          
 [7] "unidade_da_federacao"                                                 
 [8] "trimestre_codigo"                                                     
 [9] "trimestre"                                                            
[10] "variavel_codigo"                                                      
[11] "variavel"                                                             
[12] "condicao_em_relacao_a_forca_de_trabalho_e_condicao_de_ocupacao_codigo"
[13] "condicao_em_relacao_a_forca_de_trabalho_e_condicao_de_ocupacao"       

Pipe - Encadeando funções

Nos exemplos anteriores, utilizamos uma função por vez, para facilitar a compreensão de cada etapa. No entanto, à medida que nos familiarizamos com as funções, podemos encadear várias delas em um único fluxo de código usando o operador pipe (%>% ou |>). Isso torna o código mais conciso e elimina a criação de objetos intermediários desnecessários.

Porém, é importante ter cuidado para não criar sequências muito longas e difíceis de entender.

Filtrando linhas (filter())

Para responder à pergunta norteadora, não precisamos de todas as variáveis presentes na base de dados. Podemos filtrar as linhas que são relevantes para a análise, escolhendo as variáveis de interesse.

Nesse caso, podemos filtrar os dados onde a variável é igual à "Pessoas de 14 anos ou mais de idade".

dados_filtrados <- dados_renomeados |>
  filter(variavel == "Pessoas de 14 anos ou mais de idade")

Para verificar se o filtro foi feito corretamente, podemos checar o número de linhas de cada base de dados:

nrow(dados_renomeados)
[1] 27000
nrow(dados_filtrados)
[1] 6750

Podemos verificar também os valores distintos para as colunas variavel e unidade_de_medida na base de dados dados_filtrados:

dados_filtrados |>
  distinct(variavel, unidade_de_medida)
                             variavel unidade_de_medida
1 Pessoas de 14 anos ou mais de idade       Mil pessoas

Agora sabemos que a base de dados dados_filtrados contém apenas dados sobre a variável "Pessoas de 14 anos ou mais de idade", e que a unidade de medida da coluna valor é mil pessoas.

Várias formas de filtrar as linhas

Como citamos anteriormente, em algumas situações existem várias formas diferentes de realizar uma tarefa.

No caso da função filter(), podemos utilizar diferentes operadores lógicos ou funções auxiliares para fazer filtros.

Os exemplos abaixo podem ser úteis para consulta futura!

Para esses exemplos, vamos utilizar a tabela starwars do pacote dplyr. Nessa tabela, cada linha representa um personagem de Star Wars, e as colunas representam diferentes características desses personagens.

Exemplos de operadores lógicos:

Operador Descrição Exemplo Interpretação
== Igual à species == "Human" Todas as linhas cuja espécie é “Human”
!= Diferente de species != "Human" Todas as linhas cuja espécie não é “Human”
> Maior que height > 180 Todas as linhas cuja altura é maior que 180
>= Maior ou igual a height >= 180 Todas as linhas cuja altura é maior ou igual a 180
< Menor que height < 180 Todas as linhas cuja altura é menor que 180
<= Menor ou igual a height <= 180 Todas as linhas cuja altura é menor ou igual a 180
%in% Está em um conjunto species %in% c("Human", "Droid") Todas as linhas cuja espécie é “Human” ou “Droid”
! Negação !is.na(height) Todas as linhas cuja altura não é NA
! e %in% Negação de um conjunto !(species %in% c("Human", "Droid")) Todas as linhas cuja espécie não é “Human” ou “Droid”

Exemplos de funções auxiliares:

Função Descrição Exemplo Interpretação
str_detect() Detecta padrões em textos str_detect(name, "Skywalker") Todas as linhas cujo nome contém “Skywalker”
str_starts() Detecta padrões no início de textos str_starts(name, "Luke") Todas as linhas cujo nome começa com “Luke”
str_ends() Detecta padrões no final de textos str_ends(name, "Vader") Todas as linhas cujo nome termina com “Vader”

Selecionando colunas (select())

Algumas colunas não são relevantes para responder à pergunta norteadora. Podemos selecionar apenas as colunas que vamos utilizar através da função select():

dados_selecionados <-
  dados_filtrados |>
  select(
    # colunas que queremos manter
    unidade_da_federacao,
    unidade_da_federacao_codigo,
    trimestre,
    trimestre_codigo,
    condicao_em_relacao_a_forca_de_trabalho_e_condicao_de_ocupacao,
    valor
  )

glimpse(dados_selecionados)
Rows: 6,750
Columns: 6
$ unidade_da_federacao                                           <chr> "Rondôn…
$ unidade_da_federacao_codigo                                    <chr> "11", "…
$ trimestre                                                      <chr> "1º tri…
$ trimestre_codigo                                               <chr> "201201…
$ condicao_em_relacao_a_forca_de_trabalho_e_condicao_de_ocupacao <chr> "Total"…
$ valor                                                          <dbl> 1210, 7…
Várias formas de selecionar colunas

Os exemplos abaixo podem ser úteis para consulta futura!

Para esses exemplos, vamos utilizar a tabela starwars do pacote dplyr:

Exemplos de seleção de colunas:

Operador Descrição Exemplo Interpretação
: Seleciona um intervalo de colunas name:mass Todas as colunas entre name e mass
c() Seleciona colunas específicas c(name, height, mass) Apenas as colunas name, height e mass
-c() Exclui colunas específicas -c(name, height, mass) Todas as colunas, exceto name, height e mass

Exemplos de funções auxiliares:

Função Descrição Exemplo Interpretação
starts_with() Seleciona colunas que começam com um prefixo starts_with("h") Todas as colunas que começam com “h”
ends_with() Seleciona colunas que terminam com um sufixo ends_with("color") Todas as colunas que terminam com “color”
contains() Seleciona colunas que contêm um padrão contains("e") Todas as colunas que contêm “e”

Renomeando colunas (rename())

Podemos renomear colunas com a função rename(). Vamos renomear algumas colunas para facilitar o uso posteriormente:

dados_renomeados_2 <- dados_selecionados |>
  rename(
    # colunas que queremos renomear: novo_nome = nome_atual
    condicao = condicao_em_relacao_a_forca_de_trabalho_e_condicao_de_ocupacao,
    valor_mil_pessoas = valor,
    uf = unidade_da_federacao,
    uf_codigo = unidade_da_federacao_codigo
  )

glimpse(dados_renomeados_2)
Rows: 6,750
Columns: 6
$ uf                <chr> "Rondônia", "Rondônia", "Rondônia", "Rondônia", "Ron…
$ uf_codigo         <chr> "11", "11", "11", "11", "11", "11", "11", "11", "11"…
$ trimestre         <chr> "1º trimestre 2012", "1º trimestre 2012", "1º trimes…
$ trimestre_codigo  <chr> "201201", "201201", "201201", "201201", "201201", "2…
$ condicao          <chr> "Total", "Força de trabalho", "Força de trabalho - o…
$ valor_mil_pessoas <dbl> 1210, 765, 703, 62, 446, 1217, 782, 733, 49, 434, 12…

Transformando a estrutura da tabela (pivot_wider() e pivot_longer())

Ainda considerando nossa pergunta norteadora, queremos calcular a taxa de desocupação de cada estado e região do Brasil ao longo do tempo. Para isso, é mais fácil trabalhar com a tabela onde cada linha represente uma UF por trimestre, e as categorias da variável condicao sejam transformadas em colunas.

Para fazer essa transformação, podemos usar a função pivot_wider(), do pacote {tidyr}.

A função pivot_wider() é útil quando queremos reorganizar uma tabela, transformando variáveis categóricas em novas colunas. Essa estrutura facilita cálculos comparativos e análises entre as diferentes categorias.

Por exemplo, no formato atual (dados longos), temos uma linha para cada combinação de UF, trimestre e condição de ocupação. Ao usarmos pivot_wider(), vamos transformar a tabela para que cada linha represente uma UF por trimestre, e as diferentes condições de ocupação (empregado, desocupado, etc.) se tornem colunas.

dados_largos <- dados_renomeados_2 |> 
  tidyr::pivot_wider(
  names_from = condicao,
  values_from = valor_mil_pessoas,
  names_prefix = "mil_pessoas_"
)
1
names_from =: Nome da coluna de onde os nomes das novas colunas serão extraídos
2
values_from =: Nome da coluna de onde os valores para preencher as novas colunas serão extraídos
3
names_prefix =: Podemos adicionar um texto como prefixo. Nesse caso, isso é opcional, mas é útil para ficar claro qual é a unidade de medida das variáveis.
glimpse(dados_largos)
Rows: 1,350
Columns: 9
$ uf                                           <chr> "Rondônia", "Rondônia", "…
$ uf_codigo                                    <chr> "11", "11", "11", "11", "…
$ trimestre                                    <chr> "1º trimestre 2012", "2º …
$ trimestre_codigo                             <chr> "201201", "201202", "2012…
$ mil_pessoas_Total                            <dbl> 1210, 1217, 1226, 1219, 1…
$ `mil_pessoas_Força de trabalho`              <dbl> 765, 782, 784, 805, 796, …
$ `mil_pessoas_Força de trabalho - ocupada`    <dbl> 703, 733, 738, 762, 746, …
$ `mil_pessoas_Força de trabalho - desocupada` <dbl> 62, 49, 46, 42, 49, 39, 3…
$ `mil_pessoas_Fora da força de trabalho`      <dbl> 446, 434, 441, 415, 437, …

Agora temos uma tabela onde cada linha representa uma UF por trimestre, e as categorias da variável condicao se tornaram colunas. Porém agora temos colunas com nomes que estão com caracteres especiais, e podemos arrumar isso com a função clean_names().

dados_largos_renomeados <- janitor::clean_names(dados_largos)
glimpse(dados_largos_renomeados)
Rows: 1,350
Columns: 9
$ uf                                       <chr> "Rondônia", "Rondônia", "Rond…
$ uf_codigo                                <chr> "11", "11", "11", "11", "11",…
$ trimestre                                <chr> "1º trimestre 2012", "2º trim…
$ trimestre_codigo                         <chr> "201201", "201202", "201203",…
$ mil_pessoas_total                        <dbl> 1210, 1217, 1226, 1219, 1233,…
$ mil_pessoas_forca_de_trabalho            <dbl> 765, 782, 784, 805, 796, 800,…
$ mil_pessoas_forca_de_trabalho_ocupada    <dbl> 703, 733, 738, 762, 746, 761,…
$ mil_pessoas_forca_de_trabalho_desocupada <dbl> 62, 49, 46, 42, 49, 39, 36, 3…
$ mil_pessoas_fora_da_forca_de_trabalho    <dbl> 446, 434, 441, 415, 437, 443,…

As funções pivot_longer() e pivot_wider() são usadas para alternar entre dados ‘longos’ e ‘largos’. Normalmente, dados longos são mais fáceis de visualizar, enquanto dados largos são melhores para realizar cálculos comparativos entre categorias. Para cada análise, sempre existe um formato mais apropriado a considerar.

Criando e transformando colunas (mutate())

Para criar novas colunas, ou transformar colunas que já existem, podemos usar a função mutate().

Alterando os tipos de variáveis

A variável uf_codigo está armazenada como valor numérico. No entanto, como não realizaremos operações matemáticas com esses valores, é mais apropriado transformá-los em fatores, o que facilita a análise e previne erros em cálculos futuros.

Existem várias funções para transformar variáveis de um tipo para outro, como as.factor(), as.character(), as.numeric(), as.Date(), etc.

dados_tipo <- dados_largos_renomeados |>
  mutate(
    # nova variável:
    # nome_da_coluna = o que queremos calcular
    uf_codigo = as.factor(uf_codigo)
    )

Calculando a taxa de desocupação

Para calcular a taxa de desocupação, precisamos criar uma nova variável representando a proporção de pessoas desocupadas em relação ao total de pessoas economicamente ativas.

dados_com_proporcao <- dados_tipo |>
  mutate(
    prop_desocupacao = mil_pessoas_forca_de_trabalho_desocupada / mil_pessoas_forca_de_trabalho,
    perc_desocupacao = prop_desocupacao * 100
  )
1
Calculando a proporção da desocupação: para cada linha, vamos dividir o valor mil_pessoas_forca_de_trabalho_desocupada por mil_pessoas_forca_de_trabalho.
2
Multiplicando por 100 para transformar em percentual.

Criando uma variável trimestre_inicio

Podemos criar uma nova variável chamada trimestre_inicio para representar a data de início de cada trimestre. Para isso, precisaremos criar algumas outras variáveis “auxiliares” a partir da variável trimestre_codigo: ano, trimestre_numero e trimestre_mes_inicio.

dados_com_trimestre <- dados_com_proporcao |>
  mutate(
    ano = stringr::str_sub(trimestre_codigo, 1, 4),
    ano = as.numeric(ano),
    
    trimestre_numero = stringr::str_sub(trimestre_codigo, 5, 6),
    trimestre_numero = as.numeric(trimestre_numero),
    
    trimestre_mes_inicio = case_when(
      trimestre_numero == 1 ~ 1,
      trimestre_numero == 2 ~ 4,
      trimestre_numero == 3 ~ 7,
      trimestre_numero == 4 ~ 10
    ),
    
    trimestre_inicio = paste0(ano, "-", trimestre_mes_inicio, "-01"),
    trimestre_inicio = as.Date(trimestre_inicio),
    
    .after = trimestre_codigo
  ) |> 
  select(-trimestre_mes_inicio, -trimestre_numero)
1
Extrair os 4 primeiros caracteres do código do trimestre
2
Convertendo a coluna ano de texto para numérico
3
Extrair os 2 últimos caracteres do código do trimestre
4
Convertendo a coluna trimestre_numero de texto para numérico
5
Criar variável com o mês de início do trimestre
6
Criar variável com data de início do trimestre (neste momento, com tipo texto), colando os valores do mês e ano.
7
Convertendo a coluna trimestre_inicio de texto para Data
8
Queremos adicionar as colunas novas após a coluna trimestre_codigo
9
Removendo colunas que não serão necessárias

Criando uma variável dummy

Uma variável dummy é uma variável binária que indica a presença ou ausência de algum atributo.

Podemos criar uma variável dummy para identificar os trimestres que ocorreram durante o período de emergência em saúde pública de importância nacional de COVID-19. Para isso, vamos criar uma nova variável chamada periodo_pandemia, que será 1 para os trimestres que ocorreram durante a pandemia, e 0 para os demais trimestres. A função que utilizaremos é a case_when() do pacote {dplyr}.

dados_com_dummy <- dados_com_trimestre |> 
  mutate(
    periodo_pandemia = case_when(
    trimestre_codigo %in% c("202002", "202003", "202004",
                            "202101", "202102", "202103", "202104",
                            "202201") ~ 1,
    .default = 0
  ))
1
Caso o trimestre_codigo sejam um dos listados dentro do vetor, queremos salvar o valor 1 na coluna periodo_pandemia.
2
O valor padrão é 0. Se nenhuma regra listada contemplar alguma linha, a coluna criada (periodo_pandemia) receberá o valor padrão (0). Ou seja, as linhas cujo período que não estão no vetor listado receberão o valor 0.

Ordenando as linhas (arrange())

A base atual está ordada por trimestre e código da unidade da federação. Para facilitar a análise, podemos ordenar as linhas segundo a proporção de desocupação calculada no passo anterior, usando a função arrange():

dados_com_dummy |>
  select(trimestre_codigo, uf, perc_desocupacao) |>
  arrange(perc_desocupacao)
1
Selecionando colunas relevantes, para facilitar ver o resultado
2
Ordenar linhas usando a coluna perc_desocupacao, de forma crescente
# A tibble: 1,350 × 3
   trimestre_codigo uf             perc_desocupacao
   <chr>            <chr>                     <dbl>
 1 202303           Rondônia                   2.34
 2 202302           Rondônia                   2.38
 3 202303           Mato Grosso                2.42
 4 201304           Santa Catarina             2.57
 5 201204           Santa Catarina             2.69
 6 201404           Santa Catarina             2.70
 7 201402           Santa Catarina             2.83
 8 201303           Santa Catarina             2.84
 9 201403           Santa Catarina             2.95
10 202302           Mato Grosso                3.00
# ℹ 1,340 more rows

A função arrange() ordena, por padrão, de forma crescente. Podemos ordenar de forma decrescente, utilizando a função desc() junto à coluna que queremos ordenar de forma decrescente:

dados_com_dummy |>
  select(trimestre_codigo, uf, perc_desocupacao) |>
  arrange(desc(perc_desocupacao))
1
Selecionando colunas relevantes, para facilitar ver o resultado
2
Ordenar linhas usando a coluna perc_desocupacao, de forma decrescente
# A tibble: 1,350 × 3
   trimestre_codigo uf         perc_desocupacao
   <chr>            <chr>                 <dbl>
 1 202102           Pernambuco             21.8
 2 201802           Amapá                  21.7
 3 202101           Bahia                  21.7
 4 201801           Amapá                  21.6
 5 202101           Pernambuco             21.4
 6 202003           Bahia                  21.1
 7 202003           Sergipe                20.8
 8 202004           Bahia                  20.7
 9 202101           Sergipe                20.7
10 202002           Bahia                  20.5
# ℹ 1,340 more rows

Nesse caso, as linhas ficaram ordenadas de forma decrescente, de acordo com a proporção de desocupação. Porém os trimestres não estão ordenados! A função arrange() permite que ordenemos por mais de uma coluna, e a ordem de prioridade é dada pela ordem em que as colunas são passadas para a função:

dados_ordenados <- dados_com_dummy |> 
  arrange(
  # colunas que queremos usar ordenar
  trimestre_codigo, desc(prop_desocupacao)
)

glimpse(dados_ordenados)
Rows: 1,350
Columns: 14
$ uf                                       <chr> "Amapá", "Bahia", "Rio Grande…
$ uf_codigo                                <fct> 16, 29, 24, 27, 13, 28, 25, 2…
$ trimestre                                <chr> "1º trimestre 2012", "1º trim…
$ trimestre_codigo                         <chr> "201201", "201201", "201201",…
$ ano                                      <dbl> 2012, 2012, 2012, 2012, 2012,…
$ trimestre_inicio                         <date> 2012-01-01, 2012-01-01, 2012…
$ mil_pessoas_total                        <dbl> 487, 10986, 2540, 2383, 2463,…
$ mil_pessoas_forca_de_trabalho            <dbl> 318, 6888, 1370, 1173, 1558, …
$ mil_pessoas_forca_de_trabalho_ocupada    <dbl> 278, 6086, 1211, 1041, 1386, …
$ mil_pessoas_forca_de_trabalho_desocupada <dbl> 40, 802, 159, 133, 173, 99, 1…
$ mil_pessoas_fora_da_forca_de_trabalho    <dbl> 170, 4098, 1170, 1210, 905, 6…
$ prop_desocupacao                         <dbl> 0.12578616, 0.11643438, 0.116…
$ perc_desocupacao                         <dbl> 12.578616, 11.643438, 11.6058…
$ periodo_pandemia                         <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…

Agora temos a base de dados ordenada por trimestre, e dentro de cada trimestre, por proporção de desocupação (de forma descrecente).

Unindo duas bases de dados (left_join())

Unir duas tabelas é algo comum em análises de dados. Usamos operações do tipo join para combinar duas tabelas, utilizando uma ou mais colunas como “chave”. As colunas do tipo chave têm valores comuns nas duas tabelas e são usadas para identificar as linhas correspondentes entre elas.

O pacote {dplyr} fornece um conjunto de funções para realizar diferentes tipos de uniões, como left_join(), inner_join(), full_join(), entre outras.

A função left_join() é a mais frequentemente usada: ela mantém todas as linhas da primeira tabela e adiciona colunas da segunda tabela onde houver correspondência.

Exemplo 1: Introdutório

A base de dados que temos apresenta o nome e o código da UF, mas seria interessante ter a região, para futuramente usar essa variável em análises.

A base de dados importada abaixo é um arquivo .csv preparado com as informações necessárias:

uf_regiao <- readr::read_csv("https://raw.githubusercontent.com/ipeadata-lab/curso_r_intro_202409/refs/heads/main/dados/uf_regiao.csv")
Rows: 27 Columns: 3
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (2): uf_sigla, regiao
dbl (1): uf_codigo

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Vamos verificar a estrutura da base de dados uf_regiao:

glimpse(uf_regiao)
Rows: 27
Columns: 3
$ uf_sigla  <chr> "RO", "AC", "AM", "RR", "PA", "AP", "TO", "MA", "PI", "CE", …
$ uf_codigo <dbl> 11, 12, 13, 14, 15, 16, 17, 21, 22, 23, 24, 25, 26, 27, 28, …
$ regiao    <chr> "Norte", "Norte", "Norte", "Norte", "Norte", "Norte", "Norte…

Podemos tentar unir as tabelas, sem informar a chave. Quando não informamos a chave, a função buscará os nomes de colunas em comum para utilizar essas colunas como chave:

dados_ordenados |> 
  left_join(uf_regiao)
Joining with `by = join_by(uf_codigo)`
Error in `left_join()`:
! Can't join `x$uf_codigo` with `y$uf_codigo` due to incompatible types.
ℹ `x$uf_codigo` is a <factor<48524>>.
ℹ `y$uf_codigo` is a <double>.

No exemplo acima, a função left_join() tentou unir as tabelas com a coluna uf_codigo, presente nas duas tabelas.

Porém essas colunas apresentam tipos diferentes (fator e numérico). Precisamos deixá-las com o mesmo tipo para que a função left_join() consiga fazer a união corretamente. Vamos então transformar a coluna uf_codigo da tabela uf_regiao em fator:

uf_regiao_fct <- uf_regiao |> 
  mutate(uf_codigo = as.factor(uf_codigo)) 

Agora podemos unir as tabelas dados_ordenados e uf_regiao_fct:

dados_com_regiao <- dados_ordenados |>
  left_join(uf_regiao_fct) |>
  relocate(uf_sigla, regiao, .after = uf_codigo)
1
Unindo a tabela dados ordenados e uf_regiao_fct usando como chave a coluna uf_codigo.
2
Mover as colunas uf_sigla e regiao para após a coluna uf_codigo.
Joining with `by = join_by(uf_codigo)`

A nova tabela dados_com_regiao contém as colunas de uf_sigla e regiao, que foram adicionadas a partir da tabela uf_regiao_fct:

glimpse(dados_com_regiao)
Rows: 1,350
Columns: 16
$ uf                                       <chr> "Amapá", "Bahia", "Rio Grande…
$ uf_codigo                                <fct> 16, 29, 24, 27, 13, 28, 25, 2…
$ uf_sigla                                 <chr> "AP", "BA", "RN", "AL", "AM",…
$ regiao                                   <chr> "Norte", "Nordeste", "Nordest…
$ trimestre                                <chr> "1º trimestre 2012", "1º trim…
$ trimestre_codigo                         <chr> "201201", "201201", "201201",…
$ ano                                      <dbl> 2012, 2012, 2012, 2012, 2012,…
$ trimestre_inicio                         <date> 2012-01-01, 2012-01-01, 2012…
$ mil_pessoas_total                        <dbl> 487, 10986, 2540, 2383, 2463,…
$ mil_pessoas_forca_de_trabalho            <dbl> 318, 6888, 1370, 1173, 1558, …
$ mil_pessoas_forca_de_trabalho_ocupada    <dbl> 278, 6086, 1211, 1041, 1386, …
$ mil_pessoas_forca_de_trabalho_desocupada <dbl> 40, 802, 159, 133, 173, 99, 1…
$ mil_pessoas_fora_da_forca_de_trabalho    <dbl> 170, 4098, 1170, 1210, 905, 6…
$ prop_desocupacao                         <dbl> 0.12578616, 0.11643438, 0.116…
$ perc_desocupacao                         <dbl> 12.578616, 11.643438, 11.6058…
$ periodo_pandemia                         <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…

Exemplo 2: Intermediário

Um exemplo comum de uso é quando temos dados por município ou estado, e desejamos visualizar esses dados em um mapa. Para isso, precisamos de informações geoespaciais, como a delimitação geográfica de cada município ou estado. Podemos usar o left_join() para combinar esses dados geoespaciais com os dados que queremos visualizar.

Vamos usar o pacote {geobr} para carregar as geometrias dos estados brasileiros.

Dica

O pacote {geobr} facilita o acesso a dados geoespaciais do Brasil, como estados, municípios e outras divisões administrativas. Ele é muito útil quando queremos fazer análises geoespaciais, já que oferece dados geográficos prontos para uso.

Podemos utilizar a função read_state() para carregar as geometrias dos estados brasileiros. Isso nos permite combinar essas geometrias com outros dados, como taxas de desocupação, e criar mapas que facilitam a visualização de padrões regionais.

geo_estados <- geobr::read_state(showProgress = FALSE)
glimpse(geo_estados)
Rows: 27
Columns: 6
$ code_state   <dbl> 11, 12, 13, 14, 15, 16, 17, 21, 22, 23, 24, 25, 26, 27, 2…
$ abbrev_state <chr> "RO", "AC", "AM", "RR", "PA", "AP", "TO", "MA", "PI", "CE…
$ name_state   <chr> "Rondônia", "Acre", "Amazonas", "Roraima", "Pará", "Amapá…
$ code_region  <dbl> 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, …
$ name_region  <chr> "Norte", "Norte", "Norte", "Norte", "Norte", "Norte", "No…
$ geom         <MULTIPOLYGON [°]> MULTIPOLYGON (((-63.32721 -..., MULTIPOLYGON…

O left_join() é usado aqui para combinar os dados do SIDRA com os dados das delimitações das UFs. Cada linha do nosso dataset de desocupação será associada à respectiva geometria da UF, permitindo visualizarmos as proporções de desocupação por UF em um mapa. Esse tipo de operação é comum quando queremos identificar padrões regionais.

É importante garantir que as colunas usadas na combinação de tabelas (o argumento by do left_join()) tenham o mesmo tipo de dado. Podemos verificar o tipo de dado de cada coluna com a função class():

class(geo_estados$code_state)
[1] "numeric"
class(dados_com_regiao$uf_codigo)
[1] "factor"

Neste caso, as colunas que queremos usar como chave são de tipos diferentes (numérico e fator), O left_join() não conseguirá fazer a correspondência corretamente, e a função gerará um erro:

left_join(geo_estados, dados_com_regiao, by = join_by(code_state == uf_codigo))
Error in `sf_column %in% names(g)`:
! Can't join `x$code_state` with `y$uf_codigo` due to incompatible
  types.
ℹ `x$code_state` is a <double>.
ℹ `y$uf_codigo` is a <factor<48524>>.

No exemplo, podemos transformar a coluna code_state em fator usando mutate(). Assim, garantimos que as colunas usadas no argumento by sejam do mesmo tipo e possam ser corretamente combinados.

dados_geo <- geo_estados |> 
  mutate(code_state = as.factor(code_state)) |> 
  left_join(dados_com_regiao, by = join_by(code_state == uf_codigo))

glimpse(dados_geo)
Rows: 1,350
Columns: 21
$ code_state                               <fct> 11, 11, 11, 11, 11, 11, 11, 1…
$ abbrev_state                             <chr> "RO", "RO", "RO", "RO", "RO",…
$ name_state                               <chr> "Rondônia", "Rondônia", "Rond…
$ code_region                              <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
$ name_region                              <chr> "Norte", "Norte", "Norte", "N…
$ uf                                       <chr> "Rondônia", "Rondônia", "Rond…
$ uf_sigla                                 <chr> "RO", "RO", "RO", "RO", "RO",…
$ regiao                                   <chr> "Norte", "Norte", "Norte", "N…
$ trimestre                                <chr> "1º trimestre 2012", "2º trim…
$ trimestre_codigo                         <chr> "201201", "201202", "201203",…
$ ano                                      <dbl> 2012, 2012, 2012, 2012, 2013,…
$ trimestre_inicio                         <date> 2012-01-01, 2012-04-01, 2012…
$ mil_pessoas_total                        <dbl> 1210, 1217, 1226, 1219, 1233,…
$ mil_pessoas_forca_de_trabalho            <dbl> 765, 782, 784, 805, 796, 800,…
$ mil_pessoas_forca_de_trabalho_ocupada    <dbl> 703, 733, 738, 762, 746, 761,…
$ mil_pessoas_forca_de_trabalho_desocupada <dbl> 62, 49, 46, 42, 49, 39, 36, 3…
$ mil_pessoas_fora_da_forca_de_trabalho    <dbl> 446, 434, 441, 415, 437, 443,…
$ prop_desocupacao                         <dbl> 0.08104575, 0.06265985, 0.058…
$ perc_desocupacao                         <dbl> 8.104575, 6.265985, 5.867347,…
$ periodo_pandemia                         <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ geom                                     <MULTIPOLYGON [°]> MULTIPOLYGON (((…

Agora temos uma base de dados que combina os dados do SIDRA com as geometrias dos estados brasileiros.

Combinar dados dessa forma nos permite fazer visualizações geoespaciais, como um mapa de calor das taxas de desocupação por estado. Isso facilita a identificação de padrões regionais, ajudando na interpretação dos dados.

Não falaremos nesse momento sobre como criar visualizações e mapas, pois isso será abordado em aulas futuras. Mas podemos adiantar um exemplo de como criar um mapa apresentando as proporções de desocupação por estado:

Código
library(ggplot2)
dados_geo |> 
  filter(trimestre_codigo == "202402") |>
  ggplot() +
  geom_sf(aes(fill = perc_desocupacao)) +
  theme_light() +
  scale_fill_viridis_c() +
  labs(title = "Percentual de desocupação por UF no 2º trimestre de 2024",
       fill = "Desocupação (%)") +
  theme(legend.position = "bottom")

Salvando a base de dados preparada

Por fim, podemos salvar a base de dados preparada para usar nas próximas etapas. Assim não precisamos repetir todo o processo de limpeza e transformação de dados a cada vez que quisermos fazer uma análise.

É recomendável salvar a base de dados em um formato que preserve a estrutura dos dados, como .rds.

# Salvando os dados preparados
readr::write_rds(dados_com_regiao, "dados_output/sidra_4092_arrumado.rds")

Exercícios sugeridos

Utilizando a base de dados que criamos nessa aula (com a taxa de desocupação calculada), responda as perguntas abaixo.

  1. Crie uma nova tabela com apenas as colunas uf, trimestre, perc_desocupacao e periodo_pandemia.

  2. Qual foi a combinação de Estado/Trimestre que teve a maior taxa de desocupação…

    1. Durante a pandemia?
    1. Fora do período de pandemia?
  1. Considerando o trimestre mais recente disponível, qual é o estado com a maior taxa de desocupação? E a maior?

  2. Considerando o trimestre mais recente disponível, quais são os 5 estados com as maiores taxas de desocupação?

  3. Utilizando a função tidyr::pivot_wider(), como podemos criar uma tabela onde cada linha apresente dados de um estado, e cada trimestre esteja em uma coluna? Veja o exemplo abaixo:

# A tibble: 27 × 51
   uf                `1º trimestre 2012` `2º trimestre 2012` `3º trimestre 2012`
   <chr>                           <dbl>               <dbl>               <dbl>
 1 Amapá                           12.6                14.6                14.3 
 2 Bahia                           11.6                11.4                10.8 
 3 Rio Grande do No…               11.6                11.4                11.5 
 4 Alagoas                         11.3                11.7                11.6 
 5 Amazonas                        11.1                 9.06                9.51
 6 Sergipe                         10.5                11.0                10.6 
 7 Paraíba                         10.0                 9.41                8.61
 8 Pernambuco                       9.58                8.30                9.38
 9 Acre                             9.27                9.12                7.69
10 Distrito Federal                 8.80                8.49                8.69
# ℹ 17 more rows
# ℹ 47 more variables: `4º trimestre 2012` <dbl>, `1º trimestre 2013` <dbl>,
#   `2º trimestre 2013` <dbl>, `3º trimestre 2013` <dbl>,
#   `4º trimestre 2013` <dbl>, `1º trimestre 2014` <dbl>,
#   `2º trimestre 2014` <dbl>, `3º trimestre 2014` <dbl>,
#   `4º trimestre 2014` <dbl>, `1º trimestre 2015` <dbl>,
#   `2º trimestre 2015` <dbl>, `3º trimestre 2015` <dbl>, …

Sugestões de materiais

Notas de rodapé

  1. É interessante conhecer mais sobre a base de dados que estamos utilizando. O IBGE apresenta alguns conteúdos interessantes, como a página com informações sobre a PNAD Contínua Trimestral, e também a página sobre desemprego que nos ajuda a entender as variáveis presentes.↩︎