The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
Esta vinheta apresenta análises prontas do mercado de trabalho formal
usando o datacaged. Cada caso de uso é independente — você
pode executar apenas o trecho de interesse.
Dados necessários (executar uma vez):
# Novo CAGED 2023
caged_load(years = 2023, months = seq_len(12L), db_path = "caged.duckdb")
# Para casos com série histórica, adicionar:
caged_load(years = 2020:2022, months = seq_len(12L), db_path = "caged.duckdb")
caged_load(years = 2015:2019, months = seq_len(12L), db_path = "caged.duckdb")
caged_adjustments_load(years = 2015:2019, months = seq_len(12L), db_path = "caged.duckdb")Análise do fluxo mensal de entrada e saída no mercado de trabalho formal.
fluxo <- tbl(con, "caged_mov") |>
group_by(competenciamov) |>
summarise(
admissoes = sum(saldomovimentacao == 1, na.rm = TRUE),
desligamentos = sum(saldomovimentacao == -1, na.rm = TRUE),
saldo = sum(saldomovimentacao, na.rm = TRUE)
) |>
collect() |>
mutate(
data = ym(as.character(competenciamov))
) |>
arrange(data)ggplot(fluxo, aes(x = data)) +
geom_col(aes(y = admissoes), fill = "#2196F3", alpha = 0.8) +
geom_col(aes(y = -desligamentos), fill = "#F44336", alpha = 0.8) +
geom_line(aes(y = saldo), color = "#212121", linewidth = 1.2) +
geom_hline(yintercept = 0, linetype = "dashed", color = "grey40") +
scale_y_continuous(labels = label_number(scale = 1e-6, suffix = "M")) +
scale_x_date(date_breaks = "2 months", date_labels = "%b/%y") +
labs(
title = "Fluxo de Emprego Formal — Novo CAGED 2023",
subtitle = "Barras azuis = admissões | barras vermelhas = desligamentos | linha = saldo",
x = NULL,
y = "Movimentações",
caption = "Fonte: MTE/CAGED via datacaged"
) +
theme_minimal(base_size = 12) +
theme(axis.text.x = element_text(angle = 45, hjust = 1))Identifica quais setores geraram e destruíram mais empregos formais no período.
# Dicionário de seções da CNAE 2.0
cnae_secoes <- tibble::tribble(
~secao, ~descricao,
"A", "Agricultura",
"B", "Indústrias Extrativas",
"C", "Indústria de Transformação",
"D", "Eletricidade e Gás",
"E", "Água e Saneamento",
"F", "Construção",
"G", "Comércio",
"H", "Transporte",
"I", "Alojamento e Alimentação",
"J", "Informação e Comunicação",
"K", "Atividades Financeiras",
"L", "Atividades Imobiliárias",
"M", "Profissionais e Técnicas",
"N", "Atividades Administrativas",
"O", "Adm. Pública",
"P", "Educação",
"Q", "Saúde",
"R", "Artes e Cultura",
"S", "Outras Atividades",
"T", "Serviços Domésticos",
"U", "Organismos Internacionais"
)
setor <- tbl(con, "caged_mov") |>
filter(!is.na(secao)) |>
group_by(secao) |>
summarise(saldo = sum(saldomovimentacao, na.rm = TRUE)) |>
collect() |>
left_join(cnae_secoes, by = "secao") |>
mutate(
descricao = coalesce(descricao, paste("Setor", secao)),
cor = if_else(saldo >= 0, "#2196F3", "#F44336")
) |>
arrange(saldo)ggplot(setor, aes(x = saldo, y = reorder(descricao, saldo), fill = cor)) +
geom_col(show.legend = FALSE) +
geom_vline(xintercept = 0, color = "grey30") +
scale_fill_identity() +
scale_x_continuous(labels = label_number(scale = 1e-3, suffix = "k")) +
labs(
title = "Saldo de Empregos por Setor Econômico — 2023",
x = "Saldo (mil vínculos)",
y = NULL,
caption = "Fonte: MTE/CAGED via datacaged"
) +
theme_minimal(base_size = 11) +
theme(panel.grid.major.y = element_blank())Visualização de qual UF e em qual mês o emprego formal foi mais aquecido.
# Dicionário de UFs (código IBGE -> sigla)
data("uf_codigos")
uf_mensal <- tbl(con, "caged_mov") |>
group_by(uf, competenciamov) |>
summarise(saldo = sum(saldomovimentacao, na.rm = TRUE)) |>
collect() |>
left_join(uf_codigos, by = c("uf" = "codigo")) |>
filter(!is.na(sigla)) |>
mutate(
data = ym(as.character(competenciamov)),
mes = format(data, "%b")
)ggplot(uf_mensal, aes(x = mes, y = reorder(sigla, saldo), fill = saldo)) +
geom_tile(color = "white", linewidth = 0.3) +
scale_fill_gradient2(
low = "#F44336",
mid = "white",
high = "#2196F3",
midpoint = 0,
labels = label_number(scale = 1e-3, suffix = "k")
) +
labs(
title = "Saldo de Empregos por UF e Mês — 2023",
x = NULL,
y = NULL,
fill = "Saldo",
caption = "Fonte: MTE/CAGED via datacaged"
) +
theme_minimal(base_size = 10) +
theme(
axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "right"
)Caracterização demográfica dos novos vínculos formais por sexo, escolaridade e raça/cor.
# Dicionários de categorias
grau_instrucao <- tibble::tribble(
~graudeinstrucao, ~escolaridade,
1L, "Analfabeto",
2L, "Fundamental incompleto",
3L, "Fundamental completo",
4L, "Médio incompleto",
5L, "Médio completo",
6L, "Superior incompleto",
7L, "Superior completo",
8L, "Mestrado",
9L, "Doutorado"
)
raca_dic <- tibble::tribble(
~racacor, ~raca,
1L, "Indígena",
2L, "Branca",
4L, "Preta",
6L, "Amarela",
8L, "Parda",
9L, "Não informada"
)
# Admissões por escolaridade e sexo
perfil_escol <- tbl(con, "caged_mov") |>
filter(saldomovimentacao == 1, !is.na(graudeinstrucao)) |>
group_by(graudeinstrucao, sexo) |>
summarise(n = n()) |>
collect() |>
left_join(grau_instrucao, by = "graudeinstrucao") |>
mutate(
sexo_label = if_else(sexo == 1, "Masculino", "Feminino"),
escolaridade = factor(escolaridade, levels = grau_instrucao$escolaridade)
)ggplot(perfil_escol, aes(x = escolaridade, y = n, fill = sexo_label)) +
geom_col(position = "dodge") +
scale_y_continuous(labels = label_number(scale = 1e-3, suffix = "k")) +
scale_fill_manual(values = c("Masculino" = "#1565C0", "Feminino" = "#AD1457")) +
labs(
title = "Admissões por Escolaridade e Sexo — 2023",
x = NULL,
y = "Admissões (mil)",
fill = NULL,
caption = "Fonte: MTE/CAGED via datacaged"
) +
theme_minimal(base_size = 11) +
theme(
axis.text.x = element_text(angle = 40, hjust = 1),
legend.position = "top"
)# Admissões por raça/cor
perfil_raca <- tbl(con, "caged_mov") |>
filter(saldomovimentacao == 1, !is.na(racacor)) |>
group_by(racacor) |>
summarise(n = n()) |>
collect() |>
left_join(raca_dic, by = "racacor") |>
mutate(pct = n / sum(n))ggplot(perfil_raca, aes(x = reorder(raca, n), y = n, fill = raca)) +
geom_col(show.legend = FALSE) +
geom_text(aes(label = percent(pct, accuracy = 0.1)), hjust = -0.1, size = 3.5) +
coord_flip() +
scale_y_continuous(
labels = label_number(scale = 1e-6, suffix = "M"),
expand = expansion(mult = c(0, 0.15))
) +
scale_fill_brewer(palette = "Set2") +
labs(
title = "Distribuição de Admissões por Raça/Cor — 2023",
x = NULL,
y = "Admissões",
caption = "Fonte: MTE/CAGED via datacaged"
) +
theme_minimal(base_size = 11)Análise dos salários declarados nas novas contratações.
salarios <- tbl(con, "caged_mov") |>
filter(
saldomovimentacao == 1,
!is.na(salario),
salario > 0,
salario < 30000 # remove outliers extremos
) |>
select(salario, sexo, graudeinstrucao) |>
collect() |>
mutate(
sexo_label = if_else(sexo == 1, "Masculino", "Feminino"),
log_salario = log10(salario)
)
# Percentis salariais
salarios |>
group_by(sexo_label) |>
summarise(
p10 = quantile(salario, 0.10),
mediana = median(salario),
media = mean(salario),
p90 = quantile(salario, 0.90)
)ggplot(salarios, aes(x = salario, fill = sexo_label)) +
geom_histogram(
aes(y = after_stat(density)),
bins = 60,
alpha = 0.6,
position = "identity"
) +
geom_vline(
data = salarios |>
group_by(sexo_label) |>
summarise(med = median(salario)),
aes(xintercept = med, color = sexo_label),
linewidth = 1.2, linetype = "dashed"
) +
scale_x_continuous(
labels = label_dollar(prefix = "R$", big.mark = ".", decimal.mark = ","),
limits = c(0, 10000)
) +
scale_fill_manual(values = c("Masculino" = "#1565C0", "Feminino" = "#AD1457")) +
scale_color_manual(values = c("Masculino" = "#0D47A1", "Feminino" = "#880E4F")) +
labs(
title = "Distribuição Salarial das Admissões por Sexo — 2023",
subtitle = "Linhas tracejadas indicam a mediana salarial de cada grupo",
x = "Salário de admissão (R$)",
y = "Densidade",
fill = NULL,
color = NULL,
caption = "Fonte: MTE/CAGED via datacaged"
) +
theme_minimal(base_size = 11) +
theme(legend.position = "top")Construção de uma série histórica longa unindo CAGED antigo (até 2019) e Novo CAGED (2020 em diante).
# CAGED antigo: competencia + saldomovimentacao
antigo <- tbl(con, "caged_antigo") |>
filter(!is.na(competencia)) |>
group_by(competencia) |>
summarise(saldo = sum(saldomovimentacao, na.rm = TRUE)) |>
collect() |>
mutate(serie = "CAGED Antigo")
# Ajustes: somados ao antigo para corrigir a série
ajustes <- tbl(con, "caged_ajustes") |>
filter(!is.na(competencia)) |>
group_by(competencia) |>
summarise(saldo_ajuste = sum(saldomovimentacao, na.rm = TRUE)) |>
collect()
antigo_corrigido <- left_join(antigo, ajustes, by = "competencia") |>
mutate(
saldo = saldo + coalesce(saldo_ajuste, 0L),
serie = "CAGED Antigo (corrigido)"
) |>
select(competencia, saldo, serie)
# Novo CAGED: competenciamov + saldomovimentacao
novo <- tbl(con, "caged_mov") |>
group_by(competencia = competenciamov) |>
summarise(saldo = sum(saldomovimentacao, na.rm = TRUE)) |>
collect() |>
mutate(serie = "Novo CAGED")
# União das séries
serie_longa <- bind_rows(antigo_corrigido, novo) |>
filter(!is.na(competencia)) |>
mutate(data = ym(as.character(competencia))) |>
filter(data >= ym("201501")) |>
arrange(data)ggplot(serie_longa, aes(x = data, y = saldo, color = serie)) +
geom_line(linewidth = 1) +
geom_hline(yintercept = 0, linetype = "dashed", color = "grey50") +
annotate("rect",
xmin = ym("202001"), xmax = ym("202012"),
ymin = -Inf, ymax = Inf,
alpha = 0.08, fill = "orange"
) +
annotate("text",
x = ym("202006"), y = Inf, vjust = 1.5,
label = "Pandemia\nCOVID-19", size = 3, color = "darkorange"
) +
scale_y_continuous(labels = label_number(scale = 1e-6, suffix = "M")) +
scale_x_date(date_breaks = "1 year", date_labels = "%Y") +
scale_color_manual(values = c(
"CAGED Antigo (corrigido)" = "#795548",
"Novo CAGED" = "#1565C0"
)) +
labs(
title = "Saldo de Empregos Formais — Série Histórica 2015-2023",
subtitle = "Antigo CAGED corrigido pelos Ajustes + Novo CAGED",
x = NULL,
y = "Saldo mensal",
color = NULL,
caption = "Fonte: MTE/CAGED via datacaged"
) +
theme_minimal(base_size = 12) +
theme(legend.position = "top")Taxa de rotatividade (desligamentos / estoque estimado) por setor econômico.
# cnae_secoes também definido aqui para que o Caso 7 possa ser executado de forma independente
cnae_secoes <- tibble::tribble(
~secao, ~descricao,
"A", "Agricultura", "B", "Indústrias Extrativas",
"C", "Ind. de Transformação", "D", "Eletricidade e Gás",
"E", "Água e Saneamento", "F", "Construção",
"G", "Comércio", "H", "Transporte",
"I", "Alojamento e Alimentação", "J", "Informação e Comunicação",
"K", "Atividades Financeiras", "L", "Atividades Imobiliárias",
"M", "Profissionais e Técnicas", "N", "Atividades Administrativas",
"O", "Adm. Pública", "P", "Educação",
"Q", "Saúde", "R", "Artes e Cultura",
"S", "Outras Atividades", "T", "Serviços Domésticos",
"U", "Organismos Internacionais"
)
rotatividade <- tbl(con, "caged_mov") |>
filter(!is.na(secao)) |>
group_by(secao, competenciamov) |>
summarise(
admissoes = sum(saldomovimentacao == 1, na.rm = TRUE),
desligamentos = sum(saldomovimentacao == -1, na.rm = TRUE)
) |>
collect() |>
left_join(cnae_secoes, by = "secao") |>
mutate(descricao = coalesce(descricao, paste("Setor", secao))) |>
group_by(descricao) |>
summarise(
total_admissoes = sum(admissoes),
total_desligamentos = sum(desligamentos),
rotatividade_pct = total_desligamentos / (total_admissoes + total_desligamentos)
) |>
arrange(desc(rotatividade_pct))ggplot(
rotatividade |> filter(!is.na(descricao)),
aes(x = total_admissoes, y = total_desligamentos,
size = rotatividade_pct, color = rotatividade_pct,
label = descricao)
) +
geom_point(alpha = 0.7) +
geom_abline(slope = 1, intercept = 0, linetype = "dashed", color = "grey50") +
ggrepel::geom_text_repel(size = 3, max.overlaps = 12) +
scale_x_continuous(labels = label_number(scale = 1e-6, suffix = "M")) +
scale_y_continuous(labels = label_number(scale = 1e-6, suffix = "M")) +
scale_size_continuous(range = c(2, 10), guide = "none") +
scale_color_gradient(low = "#2196F3", high = "#F44336", labels = percent) +
labs(
title = "Rotatividade por Setor Econômico — 2023",
subtitle = "Pontos acima da diagonal = mais desligamentos que admissões",
x = "Admissões",
y = "Desligamentos",
color = "Rotatividade",
caption = "Fonte: MTE/CAGED via datacaged"
) +
theme_minimal(base_size = 11)Análise de qual porte de empresa concentra mais geração de empregos.
porte_dic <- tibble::tribble(
~tamestabjan, ~porte,
0L, "Não informado",
1L, "Até 4 vínculos",
2L, "5 a 9",
3L, "10 a 19",
4L, "20 a 49",
5L, "50 a 99",
6L, "100 a 249",
7L, "250 a 499",
8L, "500 a 999",
9L, "1000 ou mais"
)
porte <- tbl(con, "caged_mov") |>
filter(!is.na(tamestabjan)) |>
group_by(tamestabjan) |>
summarise(
saldo = sum(saldomovimentacao, na.rm = TRUE),
admissoes = sum(saldomovimentacao == 1, na.rm = TRUE),
desligamentos = sum(saldomovimentacao == -1, na.rm = TRUE)
) |>
collect() |>
left_join(porte_dic, by = "tamestabjan") |>
mutate(porte = factor(porte, levels = porte_dic$porte))ggplot(porte |> filter(!is.na(porte)), aes(x = porte)) +
geom_col(aes(y = admissoes), fill = "#1565C0", alpha = 0.8) +
geom_col(aes(y = -desligamentos), fill = "#B71C1C", alpha = 0.8) +
geom_point(aes(y = saldo), color = "#212121", size = 3) +
geom_hline(yintercept = 0, color = "grey30") +
scale_y_continuous(labels = label_number(scale = 1e-6, suffix = "M")) +
labs(
title = "Movimentação por Porte de Estabelecimento — 2023",
subtitle = "Azul = admissões | Vermelho = desligamentos | Ponto = saldo",
x = "Faixa de tamanho (vínculos em jan/ano)",
y = "Movimentações",
caption = "Fonte: MTE/CAGED via datacaged"
) +
theme_minimal(base_size = 11) +
theme(axis.text.x = element_text(angle = 40, hjust = 1))Comparação do mercado de trabalho formal entre as 5 regiões do Brasil.
data("uf_codigos")
regiao_mensal <- tbl(con, "caged_mov") |>
group_by(uf, competenciamov) |>
summarise(saldo = sum(saldomovimentacao, na.rm = TRUE)) |>
collect() |>
left_join(uf_codigos, by = c("uf" = "codigo")) |>
filter(!is.na(regiao)) |>
group_by(regiao, competenciamov) |>
summarise(saldo = sum(saldo), .groups = "drop") |>
mutate(data = ym(as.character(competenciamov)))ggplot(regiao_mensal, aes(x = data, y = saldo, color = regiao, fill = regiao)) +
geom_line(linewidth = 1) +
geom_area(alpha = 0.1) +
geom_hline(yintercept = 0, linetype = "dashed", color = "grey40") +
scale_y_continuous(labels = label_number(scale = 1e-3, suffix = "k")) +
scale_x_date(date_breaks = "2 months", date_labels = "%b/%y") +
scale_color_brewer(palette = "Set1") +
scale_fill_brewer(palette = "Set1") +
facet_wrap(~regiao, scales = "free_y", ncol = 2) +
labs(
title = "Saldo de Empregos Formais por Região — 2023",
x = NULL,
y = "Saldo (mil vínculos)",
color = NULL,
fill = NULL,
caption = "Fonte: MTE/CAGED via datacaged"
) +
theme_minimal(base_size = 11) +
theme(
legend.position = "none",
axis.text.x = element_text(angle = 45, hjust = 1),
strip.text = element_text(face = "bold")
)Conjunto de indicadores-chave em um painel consolidado.
# KPIs gerais do ano
kpis <- tbl(con, "caged_mov") |>
summarise(
admissoes = sum(saldomovimentacao == 1, na.rm = TRUE),
desligamentos = sum(saldomovimentacao == -1, na.rm = TRUE),
saldo = sum(saldomovimentacao, na.rm = TRUE),
salario_medio = round(mean(salario[salario > 0], na.rm = TRUE), 2),
pct_mulheres = round(mean(sexo == 3, na.rm = TRUE) * 100, 1),
pct_superior = round(mean(graudeinstrucao >= 7, na.rm = TRUE) * 100, 1)
) |>
collect()
cat(glue::glue("
=== PAINEL MERCADO DE TRABALHO FORMAL 2023 ===
Admissões: {scales::number(kpis$admissoes, big.mark = '.')}
Desligamentos: {scales::number(kpis$desligamentos, big.mark = '.')}
Saldo: {scales::number(kpis$saldo, big.mark = '.')}
Salário médio: R$ {scales::number(kpis$salario_medio, big.mark = '.', decimal.mark = ',')}
Mulheres (%): {kpis$pct_mulheres}%
Com nível sup.: {kpis$pct_superior}%
"))# Exportar qualquer resultado para Parquet via caged_to_parquet()
caged_to_parquet(
"caged.duckdb",
output_dir = "~/exports_caged"
)
# Ou particionado por UF para análises regionais
caged_to_parquet(
"caged.duckdb",
output_dir = "~/exports_caged",
tables = "caged_mov",
partition_by = "uf"
)Nota sobre os dados: os dados do CAGED estão sujeitos a revisões pelo MTE. Para análises que exigem precisão histórica, considere incorporar também os ajustes via
caged_adjustments_load().
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.