--- title: "Casos de Uso: Análise do Mercado de Trabalho" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Casos de Uso: Análise do Mercado de Trabalho} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", eval = FALSE, fig.width = 7, fig.height = 4.5 ) ``` ```{r libraries} library(datacaged) library(dplyr) library(ggplot2) library(lubridate) library(scales) ``` 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): ```{r dados-necessarios} # 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") ``` ```{r conexao} con <- caged_connect("caged.duckdb") ``` --- ## Caso 1 — Saldo de empregos: admissões vs desligamentos Análise do fluxo mensal de entrada e saída no mercado de trabalho formal. ```{r caso1-dados} 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) ``` ```{r caso1-grafico} 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)) ``` --- ## Caso 2 — Saldo por setor econômico (CNAE) Identifica quais setores geraram e destruíram mais empregos formais no período. ```{r caso2-dados} # 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) ``` ```{r caso2-grafico} 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()) ``` --- ## Caso 3 — Mapa de calor: saldo por UF e mês Visualização de qual UF e em qual mês o emprego formal foi mais aquecido. ```{r caso3-dados} # 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") ) ``` ```{r caso3-grafico} 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" ) ``` --- ## Caso 4 — Perfil do trabalhador admitido Caracterização demográfica dos novos vínculos formais por sexo, escolaridade e raça/cor. ```{r caso4-dados} # 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) ) ``` ```{r caso4-grafico-escol} 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" ) ``` ```{r caso4-dados-raca} # 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)) ``` ```{r caso4-grafico-raca} 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) ``` --- ## Caso 5 — Distribuição salarial das admissões Análise dos salários declarados nas novas contratações. ```{r caso5-dados} 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) ) ``` ```{r caso5-grafico} 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") ``` --- ## Caso 6 — Evolução do emprego formal: série 2015-2023 Construção de uma série histórica longa unindo CAGED antigo (até 2019) e Novo CAGED (2020 em diante). ```{r caso6-dados} # 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) ``` ```{r caso6-grafico} 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") ``` --- ## Caso 7 — Rotatividade por setor Taxa de rotatividade (desligamentos / estoque estimado) por setor econômico. ```{r caso7-dados} # 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)) ``` ```{r caso7-grafico} 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) ``` --- ## Caso 8 — Emprego formal por porte de estabelecimento Análise de qual porte de empresa concentra mais geração de empregos. ```{r caso8-dados} 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)) ``` ```{r caso8-grafico} 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)) ``` --- ## Caso 9 — Emprego formal nas regiões brasileiras Comparação do mercado de trabalho formal entre as 5 regiões do Brasil. ```{r caso9-dados} 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))) ``` ```{r caso9-grafico} 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") ) ``` --- ## Caso 10 — Painel executivo: resumo do mercado de trabalho Conjunto de indicadores-chave em um painel consolidado. ```{r caso10-dados} # 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}% ")) ``` ```{r caso10-parquet} # 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" ) ``` ```{r caso10-fechar} DBI::dbDisconnect(con, shutdown = TRUE) ``` --- > **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()`.