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:
sidraR);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 |
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"
)
)Antes de coletar dados, é fundamental conhecer a documentação oficial. Abaixo estão as principais fontes utilizadas neste tutorial.
| 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 |
| 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 |
| Recurso | Link |
|---|---|
| Repositório de dados eleitorais | dados.tse.jus.br |
| Base dos Dados — Candidaturas TSE | br_tse_eleicoes |
# 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áficossidraR)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.
# 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
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:
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 IDO 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)# 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)
)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)
)# 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
))Antes de publicar análises com dados raciais, verifique:
electionsBR
— dados eleitorais do TSE com abertura por raça.PNADcIBGE
— leitura de microdados da PNAD Contínua com design amostral.#> 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