Apresentação

Este tutorial é o material de apoio do workshop Como Trabalhar com Dados Raciais no Brasil, oferecido na Escola de Inverno do IESP-UERJ. O objetivo é instrumentalizar pesquisadores para o uso das principais bases de dados nacionais com abertura por cor ou raça, cobrindo desde a coleta via API até a visualização.

Ao final deste tutorial, você será capaz de:

  • Compreender os desafios metodológicos da mensuração da variável cor ou raça no Brasil;
  • Coletar dados do Censo Demográfico 2022 via API do IBGE (sidraR);
  • Consultar microdados tratados via Base dos Dados (BigQuery);
  • Construir visualizações descritivas com ggplot2.

1 · Desafio Metodológico

1.1 Autodeclaração vs. heteroidentificação

A variável cor ou raça no Brasil é capturada, nas pesquisas domiciliares do IBGE, pelo método da autodeclaração: o próprio respondente escolhe uma das cinco categorias do questionário (Branca, Preta, Amarela, Parda ou Indígena). Esse arranjo tem raízes históricas no Recenseamento de 1872 e foi consolidado a partir de 1991.

Conceito — autodeclaração vs. heteroidentificação Na autodeclaração, o respondente se classifica. Na heteroidentificação, um terceiro (como uma banca avaliadora em processos de cotas) classifica o candidato com base em fenótipo. Os dois métodos produzem distribuições diferentes e cada um tem uso adequado conforme o objetivo da pesquisa.

Tensões metodológicas relevantes:

Dimensão Autodeclaração Heteroidentificação
Unidade classificadora O próprio indivíduo Terceiro(s)
Critério Identidade subjetiva Aparência fenotípica
Uso principal Censos, PNADs Cotas, políticas afirmativas
Variação temporal Mais suscetível a mudanças Mais estável fenótipo

1.2 A categoria analítica “negros”

Uma das operações mais comuns na análise de desigualdade racial no Brasil é a soma das categorias Preta e Parda para compor a categoria analítica “Negros”. Esse procedimento tem justificativas históricas, políticas e estatísticas.

Atenção ao comunicar resultados Ao somar Pretos e Pardos, informe sempre que está usando a categoria analítica “negros” (com minúscula, sem aspas no corpo do texto após apresentado o critério), e distinga-a das categorias censitárias originais. Pesquisadores como Edward Telles e Carlos Hasenbalg documentaram que pretos e pardos compartilham posição estrutural semelhante no mercado de trabalho e no sistema educacional.

# Exemplo: construindo a categoria "negros" a partir das categorias censitárias
df <- df |>
  dplyr::mutate(
    raca_grupo = dplyr::case_when(
      cor_raca == "Preta"  ~ "Negros",
      cor_raca == "Parda"  ~ "Negros",
      cor_raca == "Branca" ~ "Brancos",
      cor_raca == "Amarela"   ~ "Amarelos",
      cor_raca == "Indígena"  ~ "Indígenas",
      is.na(cor_raca)      ~ NA_character_,   # preservar NAs explicitamente
      TRUE                 ~ "Outras/Ignorado"
    )
  )

1.3 Marcos legais relevantes

  • Lei nº 10.639/2003 — Obrigatoriedade do ensino de história e cultura afro-brasileira
  • Estatuto da Igualdade Racial (Lei nº 12.288/2010) — Define a população negra e institui obrigações do Estado
  • Lei de Cotas (Lei nº 12.711/2012) — Reserva de vagas em universidades federais
  • Resolução TSE nº 23.610/2019 e atualizações — Financiamento proporcional para candidaturas negras

2 · Fontes de Dados e Documentação

Antes de coletar dados, é fundamental conhecer a documentação oficial. Abaixo estão as principais fontes utilizadas neste tutorial.

2.1 IBGE / SIDRA

Recurso Link
SIDRA — Sistema IBGE de Recuperação Automática sidra.ibge.gov.br
Censo 2022 — Resultados do Universo Censo 2022 Universo
Tabela 9605 — População por cor ou raça (Censo 2022) Tabela 9605
Notas metodológicas do Censo 2022 Metodologia

2.2 Base dos Dados

Recurso Link
Catálogo de tabelas tratadas basedosdados.org/dataset
PNAD Contínua — Microdados br_ibge_pnadc
Censo 2022 — Microdados (Universo) br_ibge_censo_2022
Documentação do pacote R GitHub basedosdados/mais

2.3 Estatísticas Eleitorais (TSE)

Recurso Link
Repositório de dados eleitorais dados.tse.jus.br
Base dos Dados — Candidaturas TSE br_tse_eleicoes

3 · Pacotes Necessários

# Instalar pacotes caso necessário (rode apenas uma vez):
# install.packages(c("tidyverse", "sidrar", "basedosdados",
#                    "DBI", "bigrquery", "scales", "ggtext"))

library(tidyverse)   # Manipulação e visualização de dados
library(sidrar)      # API do IBGE / SIDRA
library(scales)      # Formatação de eixos em gráficos

4 · Parte 1 — Coleta via API do IBGE (sidraR)

4.1 O que é o SIDRA e como funciona o pacote

O SIDRA (Sistema IBGE de Recuperação Automática) é o portal de disseminação de dados agregados do IBGE. O pacote sidrar traduz as queries do SIDRA em chamadas de API diretamente dentro do R, sem necessidade de download manual de arquivos.

A função central é get_sidra(), que recebe os seguintes argumentos principais:

# Estrutura básica de uma query sidrar
sidrar::get_sidra(
  x          = <numero_da_tabela>,     # ID da tabela no SIDRA
  variable   = <codigo_variavel>,      # Variável de interesse (ex: 93 = pessoas)
  classific   = c("c<cod>" = <cats>),  # Classificações (ex: cor/raça, sexo)
  geo        = "Brazil",              # Nível geográfico
  geo.filter = NULL                   # Filtro geográfico (opcional)
)

Como encontrar os parâmetros? Acesse sidra.ibge.gov.br/tabela/9605, monte a consulta visualmente na interface, e então clique em “Link para esta tabela” — o URL gerado contém todos os parâmetros que get_sidra() precisa.

4.2 Tabela 9605 — População por cor ou raça (Censo 2022)

# Tabela 9605: Pessoas residentes por cor ou raça — Censo 2022
# Nível geográfico: Grandes Regiões (geo = "Region")
pop_raca <- sidrar::get_sidra(
  x        = 9605,
  variable = 93,           # Pessoas residentes
  geo      = "Region"      # Grandes Regiões do Brasil
)

# Inspecionar estrutura bruta
dplyr::glimpse(pop_raca)
#> Rows: 30
#> Columns: 13
#> $ `Nível Territorial (Código)` <chr> "2", "2", "2", "2", "2", "2", "2", "2", "…
#> $ `Nível Territorial`          <chr> "Grande Região", "Grande Região", "Grande…
#> $ `Unidade de Medida (Código)` <chr> "45", "45", "45", "45", "45", "45", "45",…
#> $ `Unidade de Medida`          <chr> "Pessoas", "Pessoas", "Pessoas", "Pessoas…
#> $ Valor                        <dbl> 17354884, 3598298, 1530418, 29467, 116543…
#> $ `Grande Região (Código)`     <chr> "1", "1", "1", "1", "1", "1", "2", "2", "…
#> $ `Grande Região`              <chr> "Norte", "Norte", "Norte", "Norte", "Nort…
#> $ `Ano (Código)`               <chr> "2022", "2022", "2022", "2022", "2022", "…
#> $ Ano                          <chr> "2022", "2022", "2022", "2022", "2022", "…
#> $ `Variável (Código)`          <chr> "93", "93", "93", "93", "93", "93", "93",…
#> $ Variável                     <chr> "População residente", "População residen…
#> $ `Cor ou raça (Código)`       <chr> "95251", "2776", "2777", "2778", "2779", …
#> $ `Cor ou raça`                <chr> "Total", "Branca", "Preta", "Amarela", "P…
# Limpeza e padronização com dplyr
pop_raca_clean <- pop_raca |>
  # Selecionar apenas colunas relevantes
  dplyr::select(
    regiao    = `Grande Região`,
    cor_raca  = `Cor ou raça`,
    populacao = Valor
  ) |>
  # Remover totais para não duplicar na visualização
  dplyr::filter(
    cor_raca != "Total",
    !is.na(populacao)           # garantir ausência de NAs
  ) |>
  # Construir a categoria analítica "Negros"
  dplyr::mutate(
    grupo = dplyr::case_when(
      cor_raca %in% c("Preta", "Parda") ~ "Negros",
      cor_raca == "Branca"              ~ "Brancos",
      cor_raca == "Amarela"             ~ "Amarelos",
      cor_raca == "Indígena"            ~ "Indígenas",
      TRUE                              ~ "Outras"
    )
  )

# Verificar resultado
head(pop_raca_clean, 10)
#>      regiao cor_raca populacao     grupo
#> 1     Norte   Branca   3598298   Brancos
#> 2     Norte    Preta   1530418    Negros
#> 3     Norte  Amarela     29467  Amarelos
#> 4     Norte    Parda  11654390    Negros
#> 5     Norte Indígena    539821 Indígenas
#> 6  Nordeste   Branca  14571557   Brancos
#> 7  Nordeste    Preta   7127018    Negros
#> 8  Nordeste  Amarela     68749  Amarelos
#> 9  Nordeste    Parda  32559846    Negros
#> 10 Nordeste Indígena    327725 Indígenas
# Agregar por grupo racial dentro de cada região
pop_grupo <- pop_raca_clean |>
  dplyr::group_by(regiao, grupo) |>
  dplyr::summarise(populacao = sum(populacao, na.rm = TRUE), .groups = "drop") |>
  # Calcular proporção dentro de cada região
  dplyr::group_by(regiao) |>
  dplyr::mutate(proporcao = populacao / sum(populacao)) |>
  dplyr::ungroup()

pop_grupo
#> # A tibble: 20 × 4
#>    regiao       grupo     populacao proporcao
#>    <chr>        <chr>         <dbl>     <dbl>
#>  1 Centro-Oeste Amarelos      60224   0.00370
#>  2 Centro-Oeste Brancos     6033785   0.370  
#>  3 Centro-Oeste Indígenas    168684   0.0104 
#>  4 Centro-Oeste Negros     10026403   0.616  
#>  5 Nordeste     Amarelos      68749   0.00126
#>  6 Nordeste     Brancos    14571557   0.267  
#>  7 Nordeste     Indígenas    327725   0.00600
#>  8 Nordeste     Negros     39686864   0.726  
#>  9 Norte        Amarelos      29467   0.00170
#> 10 Norte        Brancos     3598298   0.207  
#> 11 Norte        Indígenas    539821   0.0311 
#> 12 Norte        Negros     13184808   0.760  
#> 13 Sudeste      Amarelos     570852   0.00673
#> 14 Sudeste      Brancos    42318768   0.499  
#> 15 Sudeste      Indígenas    109934   0.00130
#> 16 Sudeste      Negros     41836761   0.493  
#> 17 Sul          Amarelos     120838   0.00404
#> 18 Sul          Brancos    21729713   0.726  
#> 19 Sul          Indígenas     81478   0.00272
#> 20 Sul          Negros      8004908   0.267

5 · Parte 2 — Consulta via Base dos Dados (BigQuery)

5.1 O ecossistema Base dos Dados

A Base dos Dados é uma organização sem fins lucrativos que trata, harmoniza e disponibiliza microdados de bases públicas brasileiras no Google BigQuery. As vantagens para pesquisadores:

  • Tabelas já com variáveis padronizadas e documentadas;
  • Possibilidade de cruzar bases distintas com SQL;
  • Infraestrutura cloud: não é necessário baixar arquivos de dezenas de GB.

5.2 Configuração inicial

Pré-requisito: conta Google e projeto no GCP Para usar o pacote basedosdados, você precisa de: 1. Uma conta Google; 2. Um projeto criado no Google Cloud Platform (o nível gratuito — free tier — oferece 1 TB/mês de consultas sem custo); 3. O pacote basedosdados instalado: install.packages("basedosdados").

library(basedosdados)
library(DBI)
library(bigrquery)

# Opção A: autenticar via arquivo de credenciais JSON (conta de serviço)
# Faça download do JSON no Console do GCP > IAM e Administrador > Contas de serviço
bigrquery::bq_auth(path = "/caminho/para/suas-credenciais.json")

# Opção B: autenticação interativa pelo navegador (mais simples para uso local)
bigrquery::bq_auth()

# Definir o ID do seu projeto de faturamento no GCP
basedosdados::set_billing_id("seu-projeto-no-gcp")  # <-- substitua pelo seu ID

5.3 Consulta SQL — Rendimento e escolaridade por cor/raça (PNAD Contínua)

O exemplo abaixo consulta a PNAD Contínua para extrair rendimento médio e anos de estudo por grupo racial. A variável V2010 é o código de cor ou raça na PNADC.

# Conectar ao projeto basedosdados via DBI
con <- DBI::dbConnect(
  bigrquery::bigquery(),
  billing = "seu-projeto-no-gcp",  # <-- substitua
  project = "basedosdados"
)

# Query SQL: rendimento médio e escolaridade por cor/raça (2022, 1º trimestre)
query_renda_raca <- "
  SELECT
    ano,
    trimestre,
    V2010                          AS cod_cor_raca,
    -- Rótulos das categorias de cor/raça da PNADC
    CASE V2010
      WHEN 1 THEN 'Branca'
      WHEN 2 THEN 'Preta'
      WHEN 4 THEN 'Parda'
      WHEN 5 THEN 'Indígena'
      WHEN 3 THEN 'Amarela'
      ELSE 'Ignorado/NA'
    END                            AS cor_raca,
    -- Rendimento habitual do trabalho principal (VD4016)
    AVG(VD4016)                    AS renda_media,
    AVG(VD3005)                    AS anos_estudo_medio,
    COUNT(*)                       AS n_pessoas
  FROM `basedosdados.br_ibge_pnadc.microdados`
  WHERE
    ano       = 2022
    AND trimestre = 1
    AND V2010 IS NOT NULL           -- excluir missings de cor/raça
    AND VD4016 IS NOT NULL          -- excluir quem não informou renda
  GROUP BY 1, 2, 3, 4
  ORDER BY renda_media DESC
"

df_renda <- DBI::dbGetQuery(con, query_renda_raca)

# Verificar
head(df_renda)
# Alternativa usando a interface bdplyr (mais próxima do tidyverse)
basedosdados::set_billing_id("seu-projeto-no-gcp")

df_lazy <- basedosdados::bdplyr("br_ibge_pnadc.microdados") |>
  dplyr::filter(ano == 2022, trimestre == 1) |>
  dplyr::select(V2010, VD4016, VD3005) |>
  dplyr::filter(!is.na(V2010), !is.na(VD4016))

# Coleta os dados do BigQuery para o R local
df_local <- basedosdados::bd_collect(df_lazy)

6 · Parte 3 — Análise Descritiva e Visualização

6.1 Paleta de cores institucional

# Paleta inspirada na identidade IESP-UERJ / tons azul-escuro
cores_raciais <- c(
  "Brancos"    = "#5baad4",   # azul-claro
  "Negros"     = "#0f2a4a",   # azul-escuro profundo
  "Indígenas"  = "#7fb3d3",   # azul-médio
  "Amarelos"   = "#a8c8e8"    # azul-pálido
)

6.2 Distribuição racial por Grande Região

# Ordenar regiões geograficamente (N → S)
ordem_regioes <- c("Norte", "Nordeste", "Centro-Oeste", "Sudeste", "Sul")

pop_grupo_plot <- pop_grupo |>
  dplyr::filter(grupo %in% names(cores_raciais)) |>
  dplyr::mutate(
    regiao = factor(regiao, levels = ordem_regioes),
    grupo  = factor(grupo, levels = c("Negros", "Brancos", "Indígenas", "Amarelos"))
  )

ggplot(pop_grupo_plot, aes(x = regiao, y = proporcao, fill = grupo)) +
  geom_col(position = "fill", width = 0.72) +
  geom_text(
    aes(label = scales::percent(proporcao, accuracy = 0.1)),
    position = position_fill(vjust = 0.5),
    color = "white", size = 3.2, fontface = "bold"
  ) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_manual(values = cores_raciais, name = NULL) +
  labs(
    title    = "Composição racial por Grande Região — Censo 2022",
    subtitle = "Categoria 'Negros' = soma de Pretos e Pardos",
    x        = NULL,
    y        = "Proporção da população",
    caption  = "Fonte: IBGE, Censo Demográfico 2022 (Tabela 9605 / SIDRA)."
  ) +
  theme_minimal(base_family = "sans") +
  theme(
    plot.title        = element_text(color = "#0f2a4a", face = "bold", size = 14),
    plot.subtitle     = element_text(color = "#4a6580", size = 11),
    plot.caption      = element_text(color = "#888888", size = 9, hjust = 0),
    axis.text.x       = element_text(color = "#0f2a4a", face = "bold", size = 11),
    axis.text.y       = element_text(color = "#555555"),
    legend.position   = "right",
    panel.grid.major.x = element_blank(),
    panel.grid.minor   = element_blank(),
    plot.background   = element_rect(fill = "#f8f9fb", color = NA),
    panel.background  = element_rect(fill = "#f8f9fb", color = NA)
  )

6.3 Desigualdade de renda simulada por grupo racial

Enquanto os dados do BigQuery não estão disponíveis localmente, usamos um dataframe simulado baseado nas estimativas da PNAD Contínua 2022 para ilustrar a análise.

Dados simulados Os valores abaixo são aproximações baseadas em publicações do IBGE (Desigualdades Sociais por Cor ou Raça no Brasil, 2022). Substitua por df_renda após executar a consulta BigQuery da seção 5.3.

# Dados simulados baseados em estimativas PNAD Contínua 2022
df_renda_sim <- tibble::tribble(
  ~cor_raca,   ~renda_media, ~anos_estudo_medio,
  "Branca",        2917,          9.8,
  "Amarela",       3282,         10.5,
  "Preta",         1563,          8.2,
  "Parda",         1533,          8.0,
  "Indígena",      1248,          7.1
) |>
  dplyr::mutate(
    grupo = dplyr::case_when(
      cor_raca %in% c("Preta", "Parda") ~ "Negros",
      TRUE                              ~ cor_raca
    ),
    # Fator para ordenar no gráfico do maior para o menor
    cor_raca = fct_reorder(cor_raca, renda_media)
  )

df_renda_sim
#> # A tibble: 5 × 4
#>   cor_raca renda_media anos_estudo_medio grupo   
#>   <fct>          <dbl>             <dbl> <chr>   
#> 1 Branca          2917               9.8 Branca  
#> 2 Amarela         3282              10.5 Amarela 
#> 3 Preta           1563               8.2 Negros  
#> 4 Parda           1533               8   Negros  
#> 5 Indígena        1248               7.1 Indígena
# Cores por categoria censitária
cores_censo <- c(
  "Branca"    = "#5baad4",
  "Amarela"   = "#a8c8e8",
  "Preta"     = "#0f2a4a",
  "Parda"     = "#1d3557",
  "Indígena"  = "#7fb3d3"
)

ggplot(df_renda_sim,
       aes(x = cor_raca, y = renda_media, fill = cor_raca)) +
  geom_col(width = 0.65, show.legend = FALSE) +
  geom_text(
    aes(label = scales::dollar(renda_media, prefix = "R$ ",
                               big.mark = ".", decimal.mark = ",")),
    hjust = -0.1, size = 3.8, color = "#0f2a4a", fontface = "bold"
  ) +
  coord_flip(clip = "off") +
  scale_y_continuous(
    labels = scales::dollar_format(prefix = "R$ ", big.mark = ".", decimal.mark = ","),
    limits = c(0, 3800)
  ) +
  scale_fill_manual(values = cores_censo) +
  labs(
    title    = "Rendimento médio mensal por cor ou raça — Brasil, 2022",
    subtitle = "Trabalho principal; pessoas de 14 anos ou mais com rendimento",
    x        = NULL,
    y        = "Rendimento médio (R$)",
    caption  = "Fonte: IBGE, PNAD Contínua 2022 (estimativas).\nNota: valores simulados para fins didáticos."
  ) +
  theme_minimal(base_family = "sans") +
  theme(
    plot.title     = element_text(color = "#0f2a4a", face = "bold", size = 13),
    plot.subtitle  = element_text(color = "#4a6580", size = 10.5),
    plot.caption   = element_text(color = "#888888", size = 9, hjust = 0),
    axis.text.y    = element_text(color = "#0f2a4a", face = "bold", size = 11),
    axis.text.x    = element_text(color = "#555555"),
    panel.grid.major.y = element_blank(),
    panel.grid.minor   = element_blank(),
    plot.background   = element_rect(fill = "#f8f9fb", color = NA),
    panel.background  = element_rect(fill = "#f8f9fb", color = NA)
  )

6.4 Razão de desigualdade branco-negro

# Calcular razão de rendimento entre grupos
razao <- df_renda_sim |>
  dplyr::group_by(grupo) |>
  dplyr::summarise(renda_grupo = mean(renda_media), .groups = "drop") |>
  dplyr::filter(grupo %in% c("Brancos", "Negros")) |>
  dplyr::summarise(
    razao = renda_grupo[grupo == "Brancos"] / renda_grupo[grupo == "Negros"]
  ) |>
  dplyr::pull(razao)

# Interpretar: para cada R$1 recebido por negros, brancos recebem R$ X
cat(sprintf(
  "Para cada R$ 1,00 recebido por negros, brancos recebem R$ %.2f\n",
  razao
))

7 · Boas Práticas e Próximos Passos

7.1 Checklist metodológico

Antes de publicar análises com dados raciais, verifique:

7.2 Recursos para aprofundamento


#> R version 4.5.2 (2025-10-31 ucrt)
#> Platform: x86_64-w64-mingw32/x64
#> Running under: Windows 11 x64 (build 26200)
#> 
#> Matrix products: default
#>   LAPACK version 3.12.1
#> 
#> locale:
#> [1] LC_COLLATE=Portuguese_Brazil.utf8  LC_CTYPE=Portuguese_Brazil.utf8   
#> [3] LC_MONETARY=Portuguese_Brazil.utf8 LC_NUMERIC=C                      
#> [5] LC_TIME=Portuguese_Brazil.utf8    
#> 
#> time zone: America/Sao_Paulo
#> tzcode source: internal
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#>  [1] scales_1.4.0    sidrar_0.2.9    lubridate_1.9.4 forcats_1.0.1  
#>  [5] stringr_1.6.0   dplyr_1.1.4     purrr_1.2.0     readr_2.1.6    
#>  [9] tidyr_1.3.1     tibble_3.3.0    ggplot2_4.0.1   tidyverse_2.0.0
#> 
#> loaded via a namespace (and not attached):
#>  [1] gtable_0.3.6       jsonlite_2.0.0     rjson_0.2.23       selectr_0.5-0     
#>  [5] compiler_4.5.2     tidyselect_1.2.1   xml2_1.4.1         jquerylib_0.1.4   
#>  [9] yaml_2.3.10        fastmap_1.2.0      R6_2.6.1           labeling_0.4.3    
#> [13] generics_0.1.4     curl_7.0.0         knitr_1.50         bslib_0.9.0       
#> [17] pillar_1.11.1      RColorBrewer_1.1-3 tzdb_0.5.0         rlang_1.1.6       
#> [21] utf8_1.2.6         stringi_1.8.7      cachem_1.1.0       xfun_0.54         
#> [25] sass_0.4.10        S7_0.2.1           timechange_0.3.0   cli_3.6.5         
#> [29] withr_3.0.2        magrittr_2.0.4     rvest_1.0.5        digest_0.6.37     
#> [33] grid_4.5.2         hms_1.1.4          lifecycle_1.0.4    vctrs_0.6.5       
#> [37] evaluate_1.0.5     glue_1.8.0         farver_2.1.2       codetools_0.2-20  
#> [41] httr_1.4.7         rmarkdown_2.30     tools_4.5.2        pkgconfig_2.0.3   
#> [45] htmltools_0.5.8.1