# Verifica se o pacman está instalado. Caso não esteja, instala o pacote.
if (!require("pacman")) install.packages("pacman")
# Carrega todos os pacotes
pacman::p_load(
tidyverse, # Pacote para manipulação de dados
readxl, # Pacote para leitura de arquivos .xls e .xlsx
lubridate, # Pacote para manipulação de datas
data.table, # Pacote para manipulação de dados
survey, # Pacote para manipulação de dados survey
srvyr # Pacote que ajusta a família tidyverse para dados survey
) Pipeline reproduzível para cálculo da Taxa de Chefia
Tratamento e tratamento dos dados da Pesquisa Distrital por Amostra de Domicílios Ampliada - 2024
Visão Geral
Este script apresenta um fluxo de trabalho reproduzível para o cálculo da taxa de chefia.
Fonte de dados
Os dados utilizados neste script são provenientes da Pesquisa Distrital por Amostra de Domicílios Ampliada - 2024.
Metodologia
A metodologia usada foi extraída do relatório “Déficit e Demanda Habitacional do Distrito Federal - 2021”, disponível no site do Instituto de Pesquisa Econômica Aplicada (IPEA) aqui.
O foco são pessoas de 24 a 64 anos, usando 3 grupos etários: 24-29, 30-39 e 40-64 anos. A taxa de chefia é calculada como a proporção de pessoas chefes de domicílio em relação ao total de pessoas em cada grupo etário:
\[ \text{Taxa de Chefia}_{i} = \frac{\text{Chefes de Domicílio}_{i}}{\text{Total de Pessoas}_{i}} \]
Onde \(i\) representa os grupos etários: 24-29, 30-39 e 40-64 anos.
Código em R - 2024
Carregar pacotes
Download dos Dados
Primeiro, é feito o download dos dados em formato .zip. A função baixar_dados_zipados é responsável por baixar o arquivo, extrair o conteúdo e identificar se ele está em .csv ou .xlsx. Como a base de moradores está em .xlsx e a de domicílios em .csv, a função é capaz de ler ambos os formatos de forma dinâmica. Por fim, ela retorna um dataframe para cada base de dados.
baixar_dados <- function(url) {
# 1. Definir arquivos e pastas temporárias
temp_zip <- tempfile(fileext = ".zip")
pasta_temp <- tempdir()
# 2. Baixar o arquivo .zip
tryCatch({
download.file(url, temp_zip, mode = "wb", quiet = TRUE)
}, error = function(e) {
stop("Erro ao baixar o arquivo. Verifique sua conexão ou a validade da URL.\nDetalhes: ", e$message)
})
# 3. Listar o que tem dentro do zip
arquivos_no_zip <- unzip(temp_zip, list = TRUE)$Name
# 4. Buscar por qualquer arquivo que termine em .csv ou .xlsx
arquivos_alvo <- arquivos_no_zip[grepl("\\.(csv|xlsx)$", arquivos_no_zip, ignore.case = TRUE)]
# Verificações de segurança
if (length(arquivos_alvo) == 0) {
unlink(temp_zip)
stop("Nenhum arquivo .csv ou .xlsx foi encontrado dentro do .zip.")
} else if (length(arquivos_alvo) > 1) {
warning("Mais de um arquivo de dados encontrado no .zip. Lendo apenas o primeiro: ", arquivos_alvo[1])
}
nome_arquivo <- arquivos_alvo[1]
# 5. Extrair o arquivo encontrado para a pasta temporária
unzip(temp_zip, files = nome_arquivo, exdir = pasta_temp)
caminho_extraido <- file.path(pasta_temp, nome_arquivo)
# 6. Identificar a extensão para escolher a função de leitura correta
extensao <- tolower(tools::file_ext(nome_arquivo))
if (extensao == "csv") {
message("Lendo arquivo CSV...")
dados <- readr::read_csv2(caminho_extraido)
} else if (extensao == "xlsx") {
message("Lendo arquivo Excel...")
dados <- readxl::read_excel(caminho_extraido)
}
# 7. Limpeza dos arquivos temporários
unlink(temp_zip)
unlink(caminho_extraido)
# 8. Retornar o dataframe
return(dados)
}
# Dados Domicílios
pdad_dom_2024 <- baixar_dados("https://pdad.ipe.df.gov.br/files/reports/domicilios.zip")
# Dados Moradores
pdad_mor_2024 <- baixar_dados("https://pdad.ipe.df.gov.br/files/reports/moradores.zip")Tratamento de Dados
Na etapa seguinte, realizamos a unificação das bases de domicílios e moradores. O cruzamento é feito utilizando as variáveis localidade, A01nficha e setor_distrito como chaves de identificação. Em seguida, os códigos numéricos originais da variável localidade são recodificados para criar a variável RA_nome.
# Fazer a junção das bases de moradores e domicílios
pdad_2024 <- pdad_dom_2024 %>%
# Trazer as informações de pessoas para domicílios
dplyr::left_join(
pdad_mor_2024,
by = c(
"localidade" = "localidade",
"A01nficha" = "A01nficha",
"setor_distrito" = "setor_distrito"
)
) %>%
# Ajustar o nome das RAs
dplyr::mutate(
RA_nome = factor(
case_when(
localidade == 5301 ~ 'Plano Piloto',
localidade == 5302 ~ 'Gama',
localidade == 5303 ~ 'Taguatinga',
localidade == 5304 ~ 'Brazlândia',
localidade == 5305 ~ 'Sobradinho',
localidade == 5306 ~ 'Planaltina',
localidade == 5307 ~ 'Paranoá',
localidade == 5308 ~ 'Núcleo Bandeirante',
localidade == 5309 ~ 'Ceilândia',
localidade == 5310 ~ 'Guará',
localidade == 5311 ~ 'Cruzeiro',
localidade == 5312 ~ 'Samambaia',
localidade == 5313 ~ 'Santa Maria',
localidade == 5314 ~ 'São Sebastião',
localidade == 5315 ~ 'Recanto Das Emas',
localidade == 5316 ~ 'Lago Sul',
localidade == 5317 ~ 'Riacho Fundo',
localidade == 5318 ~ 'Lago Norte',
localidade == 5319 ~ 'Candangolândia',
localidade == 5320 ~ 'Águas Claras',
localidade == 5321 ~ 'Riacho Fundo II',
localidade == 5322 ~ 'Sudoeste e Octogonal',
localidade == 5323 ~ 'Varjão',
localidade == 5324 ~ 'Park Way',
localidade == 5325 ~ 'SCIA',
localidade == 5326 ~ 'Sobradinho II',
localidade == 5327 ~ 'Jardim Botânico',
localidade == 5328 ~ 'Itapoã',
localidade == 5329 ~ 'SIA',
localidade == 5330 ~ 'Vicente Pires',
localidade == 5331 ~ 'Fercal',
localidade == 5332 ~ 'Sol Nascente / Pôr do Sol',
localidade == 5333 ~ 'Arniqueira',
localidade == 5334 ~ 'Arapoanga',
localidade == 5335 ~ 'Água Quente',
localidade == 5336 ~ 'Área Rural',
localidade == 5241 ~ 'Águas Lindas de Goiás',
localidade == 5242 ~ 'Alexânia',
localidade == 5243 ~ 'Cidade Ocidental',
localidade == 5244 ~ 'Cristalina',
localidade == 5245 ~ 'Cocalzinho de Goiás',
localidade == 5246 ~ 'Formosa',
localidade == 5247 ~ 'Luziânia',
localidade == 5248 ~ 'Novo Gama',
localidade == 5249 ~ 'Padre Bernardo',
localidade == 5250 ~ 'Planaltina de Goiás',
localidade == 5251 ~ 'Santo Antônio do Descoberto',
localidade == 5252 ~ 'Valparaíso de Goiás'
)
)
)
# Excluir as bases parciais
rm(pdad_dom_2024, pdad_mor_2024)Expansão da amostra
Nesta etapa, configuramos o desenho amostral da pesquisa para garantir que as estimativas representem corretamente a população. Primeiro, utilizamos a função svydesign do pacote survey para declarar a estrutura da amostra, definindo a ficha (A01nficha) como a unidade primária, o setor (setor_distrito) como estrato e o peso_mor como fator de expansão. Em seguida, convertemos esse objeto estatístico clássico para o formato de tibble através da função as_survey do pacote srvyr.
# Declarar o desenho incial
sample_pdad <-
survey::svydesign(id = ~A01nficha, # Identificador único da unidade amostrada
strata = ~setor_distrito, # Identificação do estrato
weights = ~peso_mor, # Inverso da fração amostral
nest = TRUE, # Parâmetro de tratamento para os IDs dos estratos
data = pdad_2024 # Declarar a base a ser utilizada
)
# Ajustar objeto de amostra, para uso com o pacote srvyr (como tibble)
amostra_mor <- srvyr::as_survey(sample_pdad)Resultados e inferências
Primeiro é calculada a taxa de chefia por grupo etário, utilizando a variável idade_calculada para criar os grupos etários (24-29, 30-39 e 40-64 anos). Em seguida, é feita uma filtragem para considerar apenas os chefes de domicílio (E04==1) e o total de chefes é calculado para cada grupo etário.
# Calcular a taxa de chefia por grupo etário.
tx_chefia <- amostra_mor %>%
srvyr::mutate(grupo_etario = case_when(idade_calculada %in% c(24:29) ~ "idade_24_29",
idade_calculada %in% c(30:39) ~ "idade_30_39",
idade_calculada %in% c(40:64) ~ "idade_40_64")) %>%
srvyr::filter(E04==1) %>%
srvyr::group_by(grupo_etario) %>%
srvyr::summarise(total_chefes=survey_total(vartype = c("cv", "ci")))
tx_chefia <- subset(tx_chefia, !is.na(grupo_etario))
# Calcular o total de pessoas na população.
pop_total <- amostra_mor %>%
srvyr::mutate(
grupo_etario = case_when(
idade_calculada %in% c(24:29) ~ "idade_24_29",
idade_calculada %in% c(30:39) ~ "idade_30_39",
idade_calculada %in% c(40:64) ~ "idade_40_64"
)
) %>%
srvyr::group_by(grupo_etario) %>%
srvyr::summarise(pop_total = survey_total(vartype = c("cv", "ci")))
pop_total <- subset(pop_total,!is.na(grupo_etario))
# Juntar as tabelas para calcular a taxa de chefia por idade.
tx_chefia_idade <- cbind(tx_chefia, pop_total[, -1])
tx_chefia_idade$tx_chefia <- tx_chefia_idade$total_chefes / tx_chefia_idade$pop_total
# Teste para ver se é possível fazer inferência sobre os dados.
# Necessário coeficiente de variação (cv) menor do que 25%
tx_chefia_idade <- as.data.frame(tx_chefia_idade)
tx_chefia_idade$tx_chefia <-
ifelse(tx_chefia_idade$total_chefes_cv > 0.25,
NA,
tx_chefia_idade$tx_chefia)
rm(tx_chefia, pop_total)Após o cálculo da taxa de chefia por grupo etário, o mesmo processo é repetido para calcular a taxa de chefia por grupo etário e região administrativa (RA). A variável RA_nome é utilizada para identificar as RAs, e a taxa de chefia é calculada para cada combinação de grupo etário e RA.
# Cálculo a taxa de chefia por idade e RA.
tx_chefia_idade_ra <- amostra_mor %>%
srvyr::mutate(grupo_etario = case_when(idade_calculada %in% c(24:29) ~ "idade_24_29",
idade_calculada %in% c(30:39) ~ "idade_30_39",
idade_calculada %in% c(40:64) ~ "idade_40_64")) %>%
srvyr::filter(E05==1) %>%
srvyr::group_by(grupo_etario, localidade) %>%
srvyr::summarise(total_chefes=survey_total(vartype = c("cv", "ci")))
tx_chefia_idade_ra <- subset(tx_chefia_idade_ra, !is.na(grupo_etario))
pop_idade_ra <- amostra_mor %>%
srvyr::mutate(grupo_etario = case_when(idade_calculada %in% c(24:29) ~ "idade_24_29",
idade_calculada %in% c(30:39) ~ "idade_30_39",
idade_calculada %in% c(40:64) ~ "idade_40_64")) %>%
srvyr::group_by(grupo_etario, localidade) %>%
srvyr::summarise(pop_total=survey_total(vartype = c("cv", "ci")))
pop_idade_ra <- subset(pop_idade_ra, !is.na(grupo_etario))
tx_chefia_idade_raf <-
cbind(tx_chefia_idade_ra, pop_idade_ra[, -c(1, 2)])
tx_chefia_idade_raf$tx_chefia <-
tx_chefia_idade_raf$total_chefes / tx_chefia_idade_raf$pop_total
tx_chefia_idade_raf <-
subset(tx_chefia_idade_raf,!is.na(grupo_etario))
# Teste para ver se inferências podem ser feitas
tx_chefia_idade_raf <- as.data.frame(tx_chefia_idade_raf)
tx_chefia_idade_raf$tx_chefia <-
ifelse(tx_chefia_idade_raf$total_chefes_cv > 0.25,
NA,
tx_chefia_idade_raf$tx_chefia)Código em R - 2021
Leitura dos Dados
Os links do antigo código para a base de dados estão quebrados, assim, pelo curto espaço de tempo, os arquivos estão sendo lidos localmente.
pdad_dom_2021 <- read_csv2('dados/01_bruto/PDAD_2021-Domicilios.csv')
pdad_mor_2021 <- read_csv2('dados/01_bruto/PDAD_2021-Moradores.csv')Tratamento dos Dados
Primeiro, juntou-se os banco de moradores com o de domicílios. Após isso, as variável A01_ra foi decodificada.
# Fazer a junção das bases de moradores e domicílios
pdad_2021 <- pdad_dom_2021 %>%
# Trazer as informações de pessoas para domicílios
dplyr::left_join(
pdad_mor_2021 #%>%
#dplyr::select(-FATOR_PROJ)
,
by = c(
"A01ra" = "A01ra",
"A01nficha" = "A01nficha",
"A01setor" = "A01setor"
)
) %>%
# Ajustar o nome das RAs
dplyr::mutate(
RA_nome = factor(
case_when(
A01ra == 1 ~ "Plano Piloto",
A01ra == 2 ~ "Gama",
A01ra == 3 ~ "Taguatinga",
A01ra == 4 ~ "Brazlândia",
A01ra == 5 ~ "Sobradinho",
A01ra == 6 ~ "Planaltina",
A01ra == 7 ~ "Paranoá",
A01ra == 8 ~ "Núcleo Bandeirante",
A01ra == 9 ~ "Ceilândia",
A01ra == 10 ~ "Guará",
A01ra == 11 ~ "Cruzeiro",
A01ra == 12 ~ "Samambaia",
A01ra == 13 ~ "Santa Maria",
A01ra == 14 ~ "São Sebastião",
A01ra == 15 ~ "Recanto das Emas",
A01ra == 16 ~ "Lago Sul",
A01ra == 17 ~ "Riacho Fundo",
A01ra == 18 ~ "Lago Norte",
A01ra == 19 ~ "Candangolândia",
A01ra == 20 ~ "Águas Claras",
A01ra == 21 ~ "Riacho Fundo II",
A01ra == 22 ~ "Sudoeste/Octogonal",
A01ra == 23 ~ "Varjão",
A01ra == 24 ~ "Park Way",
A01ra == 25 ~ "SCIA/Estrutural",
A01ra == 26 ~ "Sobradinho II",
A01ra == 27 ~ "Jardim Botânico",
A01ra == 28 ~ "Itapoã",
A01ra == 29 ~ "SIA",
A01ra == 30 ~ "Vicente Pires",
A01ra == 31 ~ "Fercal",
A01ra == 32 ~ "Sol Nascente/Pôr do Sol",
A01ra == 33 ~ "Arniqueira"
)
)
)
# Excluir as bases parciais
rm(pdad_dom_2021, pdad_mor_2021)Expansão da amostra
Nesta etapa, configuramos o desenho amostral da pesquisa para garantir que as estimativas representem corretamente a população. Primeiro, utilizamos a função svydesign do pacote survey para declarar a estrutura da amostra, definindo a ficha (A01nficha) como a unidade primária, o setor (A01setor) como estrato e o PESO_MOR como fator de expansão. Em seguida, é feita uma correção pó-extrato e por fim convertemos esse objeto estatístico clássico para o formato de tibble através da função as_survey do pacote srvyr.
# Declarar o desenho incial
sample_pdad <-
survey::svydesign(id = ~A01nficha, # Identificador único da unidade amostrada
strata = ~A01setor, # Identificação do estrato
weights = ~PESO_MOR, # Inverso da fração amostral
nest = TRUE, # Parâmetro de tratamento para os IDs dos estratos
data = pdad_2021 # Declarar a base a ser utilizada
)
# Criar um objeto para pós estrato
post_pop <- pdad_2021 %>%
dplyr::group_by(POS_ESTRATO) %>% # Agrupar por pós-estrato
dplyr::summarise(Freq=max(POP_AJUSTADA_PROJ)) # Capturar o total da população
# Declarar o objeto de pós-estrato
# Estamos dizendo nesse passo qual é a população alvo para cada
# pós-estrato considerado
amostra <-
survey::postStratify(sample_pdad, ~ POS_ESTRATO, post_pop)
# Ajustar para tratamento de estratos com apenas uma UPA (adjust=centered)
options(survey.lonely.psu = "adjust")
# Ajustar objeto de amostra, para uso com o pacote srvyr (como tibble)
amostra_mor <- srvyr::as_survey(amostra)
# Exclui arquivos não mais usados
rm(amostra, sample_pdad, post_pop, pdad_2021)Resultados e inferências
# Calculando a taxa de chefia por grupo etário.
tx_chefia <- amostra_mor %>%
srvyr::mutate(grupo_etario = case_when(idade %in% c(24:29) ~ "idade_24_29",
idade %in% c(30:39) ~ "idade_30_39",
idade %in% c(40:64) ~ "idade_40_64")) %>%
srvyr::filter(E05==1) %>%
srvyr::group_by(grupo_etario) %>%
srvyr::summarise(total_chefes=survey_total(vartype = c("cv", "ci")))
tx_chefia <- subset(tx_chefia, !is.na(grupo_etario))
# Calculando o total de pessoas na população.
pop_total <- amostra_mor %>%
srvyr::mutate(
grupo_etario = case_when(
idade %in% c(24:29) ~ "idade_24_29",
idade %in% c(30:39) ~ "idade_30_39",
idade %in% c(40:64) ~ "idade_40_64"
)
) %>%
srvyr::group_by(grupo_etario) %>%
srvyr::summarise(pop_total = survey_total(vartype = c("cv", "ci")))
pop_total <- subset(pop_total,!is.na(grupo_etario))
# Juntando as tabelas para calcular a taxa de chefia por idade.
tx_chefia_idade_21 <- cbind(tx_chefia, pop_total[, -1])
tx_chefia_idade_21$tx_chefia <-
tx_chefia_idade_21$total_chefes / tx_chefia_idade_21$pop_total
# Teste para ver se é possível fazer inferência sobre os dados.
# Necessário coeficiente de variação (cv) menor do que 25%
tx_chefia_idade_21 <- as.data.frame(tx_chefia_idade_21)
tx_chefia_idade_21$tx_chefia <-
ifelse(tx_chefia_idade_21$total_chefes_cv > 0.25,
NA,
tx_chefia_idade_21$tx_chefia)
rm(tx_chefia, pop_total)# Cálculo a taxa de chefia por idade e RA.
tx_chefia_idade_ra <- amostra_mor %>%
srvyr::mutate(grupo_etario = case_when(idade %in% c(24:29) ~ "idade_24_29",
idade %in% c(30:39) ~ "idade_30_39",
idade %in% c(40:64) ~ "idade_40_64")) %>%
srvyr::filter(E05==1) %>%
srvyr::group_by(grupo_etario, RA_nome) %>%
srvyr::summarise(total_chefes=survey_total(vartype = c("cv", "ci")))
tx_chefia_idade_ra <- subset(tx_chefia_idade_ra, !is.na(grupo_etario))
pop_idade_ra <- amostra_mor %>%
srvyr::mutate(grupo_etario = case_when(idade %in% c(24:29) ~ "idade_24_29",
idade %in% c(30:39) ~ "idade_30_39",
idade %in% c(40:64) ~ "idade_40_64")) %>%
srvyr::group_by(grupo_etario, RA_nome) %>%
srvyr::summarise(pop_total=survey_total(vartype = c("cv", "ci")))
pop_idade_ra <- subset(pop_idade_ra, !is.na(grupo_etario))
tx_chefia_idade_raf_21 <-
cbind(tx_chefia_idade_ra, pop_idade_ra[, -c(1, 2)])
tx_chefia_idade_raf_21$tx_chefia <-
tx_chefia_idade_raf_21$total_chefes / tx_chefia_idade_raf_21$pop_total
tx_chefia_idade_raf_21 <-
subset(tx_chefia_idade_raf_21,!is.na(grupo_etario))
# Teste para ver se inferências podem ser feitas
tx_chefia_idade_raf_21 <- as.data.frame(tx_chefia_idade_raf_21)
tx_chefia_idade_raf_21$tx_chefia <-
ifelse(tx_chefia_idade_raf_21$total_chefes_cv > 0.25,
NA,
tx_chefia_idade_raf_21$tx_chefia)Gráficos
Taxa Chefia por idade em 2024
dados <- tx_chefia_idade
# Formatar os nomes para o eixo X
dados$grupo_etario_formatado <- factor(dados$grupo_etario,
levels = c("idade_24_29", "idade_30_39", "idade_40_64"),
labels = c("Entre 24 a 29 anos", "Entre 30 a 39 anos", "Entre 40 a 64 anos"))
# Criar o gráfico
ggplot(dados, aes(x = grupo_etario_formatado, y = tx_chefia, fill = grupo_etario_formatado)) +
geom_bar(stat = "identity", size = 0.3) +
geom_text(aes(label = scales::percent(tx_chefia, accuracy = 0.01)),
vjust = -0.5,
size = 4,
color = "black",
fontface = "bold") +
scale_fill_manual(values = c("Entre 24 a 29 anos" = "#8c8c8c",
"Entre 30 a 39 anos" = "#e3d17c",
"Entre 40 a 64 anos" = "#b09e33")) +
scale_y_continuous(labels = scales::percent_format(accuracy = 1),
limits = c(0, 0.65),
breaks = seq(0, 0.6, 0.1)) +
theme_minimal() +
theme(
axis.title.x = element_blank(),
axis.text.x = element_text(angle = 0, hjust = 0.5, face = "bold", size = 10, color = "black"),
axis.text.y = element_text(size = 10, color = "black"),
panel.grid.major = element_line(color = "grey95"),
panel.grid.minor = element_blank(),
axis.line.x = element_line(color = "grey", size = 0.5),
legend.position = "none"
) +
labs(y = "Taxa de Chefia")Taxa Chefia por idade em 2024 e 2021
dados <- tx_chefia_idade |>
select(
grupo_etario,
tx_chefia_24 = tx_chefia
) |>
left_join(
tx_chefia_idade_21 |>
select(
grupo_etario,
tx_chefia_21 = tx_chefia
)
) |>
pivot_longer(
cols = c(tx_chefia_24, tx_chefia_21),
names_to = "ano",
values_to = "taxa"
)
dados$grupo_etario <- factor(dados$grupo_etario,
levels = c("idade_24_29", "idade_30_39", "idade_40_64"),
labels = c("Entre 24 a 29 anos", "Entre 30 a 39 anos", "Entre 40 a 64 anos"))
dados$ano <- factor(dados$ano,
levels = c("tx_chefia_21", "tx_chefia_24"),
labels = c("2021", "2024"))
ggplot(dados, aes(x = grupo_etario, y = taxa, fill = ano)) +
geom_col(position = position_dodge(width = 0.8), width = 0.7) +
geom_text(aes(label = scales::percent(taxa, accuracy = 0.1)),
position = position_dodge(width = 0.8),
vjust = -0.5,
size = 3.5,
fontface = "bold") +
scale_fill_manual(values = c("2021" = "#d3d3d3", "2024" = "#b09e33")) +
scale_y_continuous(labels = scales::percent_format(), limits = c(0, 0.65)) +
theme_minimal() +
theme(
axis.title.x = element_blank(),
axis.text.x = element_text(face = "bold", color = "black"),
legend.position = "top",
legend.title = element_blank(),
panel.grid.minor = element_blank()
) +
labs(y = "Taxa de Chefia")