Introdução

Este documento é um projeto de obtenção, limpeza, armazenamento e análise de dados da área da saúde. Foi criado para compor meu portfólio pessoal. O documento está dividido em etapas que estão separadas em abas de navegação na página.

Etapas:

  1. Obtenção, limpeza e organização de dados;
  2. Criação de um Banco de dados no PostgreSQL e armazenamento dos dados;
  3. Seleção dos dados do BD; 4 Codigos das análises exploratórias dos dados;
  4. Apresentação dos resultados.

Os dados utilizados foram obtidos do Portal Brasileiro de Dados Abertos na página do Sistema de Informaçãoo sobre Mortalidade - SIM que contém dados de 1979 a 2018. Os dados disponibilizados contém 87 ariáveis que estão descritas em um documento.

Para as análises deste relatório foram utilizados os dados entre os anos de 2015 a 2018. e foram utilizadas as seguintes variáveis:

DTOBITO = Data em que occoreu o Óbito (Data no padrão ddmmaaaa)

DTNASC = Data do nascimento do falecido. Em caso de Óbito fetal as datas de Óbitoe nascimento deverão ser iguais.(Data no padrão ddmmaaaa)

ESC = Escolaridade em anos. (1 - Nenhuma; 2 - de 1 a 3 anos; 3 - de 4 a 7 anos; 4- de 8 a 11 anos; 5 - 12 anos e mais; 9 - Ignorado)

ESTCIV = Estado civil. (1: Solteiro; 2: Casado; 3: Viúvo; 4: Separado judicialmente; 5: União consensual; 9: Ignorado)

HORAOBITO = Horário do Óbito. (Números (padrão 24 horas 00:00))

IDADE = Idade do falecido em minutos, horas, dias, meses ou anos. (Idade: composto de dois subcampos. - O primeiro, de 1 dígito, indica a unidade da idade (se 1 = minuto, se 2 = hora, se 3 = mês, se 4 = ano, se = 5 idade maior que 100 anos). - O segundo, de dois dígitos, indica a quantidade de unidades: Idade menor de 1 hora: subcampo varia de 01 e 59 (minutos); De 1 a 23 Horas: subcampo varia de 01 a 23 (horas); De 24 horas e 29 dias: subcampo varia de 01 a 29 (dias); De 1 a menos de 12 meses completos: subcampo varia de 01 a 11 (meses); Anos - subcampo varia de 00 a 99; - 9 - ignorado). Esta coluna será dividida em duas novas colunas antes da insersão no BD (CODIDADE e VALIDADE)

SEXO = Sexo do falecido. - Ignorado em casos especiais como cadáveres mutilados, em estado avançado de decomposição, genitáia indefinida ou hermafroditismo. (M - masculino; F - feminino; I - ignorado)

Pacotes utilizados no projeto

require(ggplot2) # pacote para a criação dos gráficos
require(ggpubr) # Configuraçõe de plots
require(ggthemes) # Temas diferentes para o ggplot
require(hrbrthemes) # Temas diferentes para o ggplot
require(viridis) # Para as paletas de cores
require(RPostgreSQL) # Conexão com o BD
require(lubridate) # Configuração de data e hora
require(stringr) # Edição de texto (Regex)
require(dplyr) # Organização de dados
require(scales)

1. Download e preparação

Nesta sessãoo os dados são obtidos através de um link que foi extraído da inspeção da página do SIM. O link foi utilizado como base para criação de um loop para download dos dados. Os dados foram armazenados em um arquivo temporário, carregados e combinados a cada volta do loop.

A planilha obtida após combinar os dados foi utilizada para filtrar somente as variáveis de interesse, que foram descritas na introdução deste documento.

# Sequencia dos anos que serãoo baixados
anos <- seq(2015, 2018, by = 1)
# Cria um DF vazio para armazenar os resultados do loop
dados_combinados <- data.frame()

# Loop para baixar os dados
for(i in 1:length(anos)){
  # Criação da URL
  url <- paste0("https://s3-sa-east-1.amazonaws.com/ckan.saude.gov.br/SIM/Mortalidade_Geral_", anos[i] ,".csv")
  
  # Download dos dados
  download.file(url, destfile = "C:\\Users\\user\\Downloads\\temp.csv")
  
  # Leitura e separação das colunas de interesse
  dados <- read.csv2("C:\\Users\\user\\Downloads\\temp.csv")
  head(dados)
  dados <- dados[, c("DTOBITO","DTNASC","ESC","ESTCIV","HORAOBITO","IDADE","SEXO")]
  
  # Combinar os dados
  dados_combinados <- rbind(dados_combinados, dados)
  
  # Remove o arquivo temporário após combinar a última planilha
  file.remove("C:\\Users\\user\\Downloads\\temp.csv")
}

A seguir os dados serão configurados para que sejam identificados no formato correto. Foram feitas alterações nas colunas que continhas datas (DTOBITO e DTNASC), e a coluna IDADE foi separada em duas novas colunas, CODIDADE que contém os códigos que identificam a unidade de tempo da nova coluna VALIDADE que contém o número de unidades.

# Configurar as colunas de data - caso o dia contenha comente um dígito serão incluído um zero no início.
dados_combinados$DTOBITO <- ifelse(str_count(dados_combinados$DTOBITO) == 7, paste0("0",dados_combinados$DTOBITO), dados_combinados$DTOBITO)
dados_combinados$DTOBITO <- dmy(dados_combinados$DTOBITO)

dados_combinados$DTNASC <- ifelse(str_count(dados_combinados$DTNASC) == 7, paste0("0",dados_combinados$DTNASC), dados_combinados$DTNASC)
dados_combinados$DTNASC <- dmy(dados_combinados$DTNASC)

# Separa os dados da coluna idade em CODIDADE: código identificador da unidade de tempo, e em VALIDADE: número de unidades de tempo.
dados_combinados$CODIDADE <- as.integer(str_sub(dados_combinados$IDADE,1,1))
dados_combinados$VALIDADE <- as.integer(str_sub(dados_combinados$IDADE, 2))  

# Excluir a antiga coluna idade
dados_combinados$IDADE <- NULL

# Configura os dados de hora
dados_combinados$HORAOBITO <- str_pad(dados_combinados$HORAOBITO, 4, pad = "0")
dados_combinados$HORAOBITO <- ifelse(!is.na(dados_combinados$HORAOBITO),  paste0(str_sub(dados_combinados$HORAOBITO, start = 1, end = 2), ":", str_sub(dados_combinados$HORAOBITO, start = 3, end = 4)), "NA")

# Salvar os dados processados em um arquivo .csv para insersão no BD
write.csv(dados_combinados, file = 'C:\\InfraServer\\Backup\\DadosTratamento\\temp_comb.csv', row.names = F)

2. Banco de dados

Os Códigos abaixo contém a criação do Banco de dados e a insersão dos dados que foram processados no bloco de código anterior. Os dados haviam sido salvos em um arquivo .csv temporário que é apagado ao final da insersão dos dados no BD.

# Configura a conexão com o BD
drv <- dbDriver("PostgreSQL")
con <- dbConnect(drv, db = "postgres", user = "postgres", password = "postgres123", host = "localhost", port = 5432)


# Cria o Schema para armazenar as tabelas dos obitos e as tabelas com as categorias das variáveis
dbGetQuery(con, "DROP SCHEMA IF EXISTS obitos_brasil_sim CASCADE;")
dbGetQuery(con, "CREATE SCHEMA obitos_brasil_sim;")

# Cria a tabela com os dados dos óbitos
dbGetQuery(con, "CREATE TABLE obitos_brasil_sim.obitos(
           DTOBITO timestamp without time zone, 
           DTNASC timestamp without time zone,
           ESC integer,
           ESTCIV integer,
           HORAOBITO character(5),
           SEXO integer,
           CODIDADE integer,
           VALIDADE integer
);")

dbGetQuery(con, "CREATE INDEX obitos_sexo
           ON obitos_brasil_sim.obitos
           USING btree (SEXO);")

dbGetQuery(con, "CREATE INDEX obitos_codidade
           ON obitos_brasil_sim.obitos
           USING btree (CODIDADE);")

dbGetQuery(con, "CREATE INDEX obitos_estciv
           ON obitos_brasil_sim.obitos
           USING btree (ESTCIV);")

dbGetQuery(con, "CREATE INDEX obitos_esc
           ON obitos_brasil_sim.obitos
           USING btree (ESC);")


dbDisconnect(con)
dbGetQuery(con, "COPY obitos_brasil_sim.obitos(
                  DTOBITO,DTNASC,ESC,ESTCIV,HORAOBITO,SEXO,CODIDADE,VALIDADE)
                  FROM 'C:\\InfraServer\\Backup\\DadosTratamento\\temp_comb.csv'
                  WITH (FORMAT csv, HEADER, DELIMITER ',', NULL 'NA');")
                  
file.remove('C:\\InfraServer\\Backup\\DadosTratamento\\temp_comb.csv')

Abaixo serão criadas as tabelas que explicam as variávies categóricas. Os dados serão criados de acordo com a legenda fornecida no documento citado no início.

# Cria os dados dos niveis das variaveis categoricas.
escolaridade <- data.frame("ESC" = c(1,2,3,4,5,9), "ESC_NIVEL" = c("Nenhuma", "1 a 3 anos", "4 a 7 anos", "8 a 11 anos", "2 anos e mais", "Ignorado"))
est_civil <- data.frame("ESTCIV" = c(1,2,3,4,5,9), "ESTCIV_NIVEL" = c("Solteiro","Casado","Viuvo","Separado judicialmente","Uniao consensual","Ignorado"))

write.csv(escolaridade,'C:\\InfraServer\\Backup\\DadosTratamento\\escolaridade_temp.csv', row.names = F)
write.csv(est_civil,'C:\\InfraServer\\Backup\\DadosTratamento\\estacv_temp.csv', row.names = F)

# Configura a conexão com o BD
drv <- dbDriver("PostgreSQL")
con <- dbConnect(drv, db = "postgres", user = "postgres", password = "postgres123", host = "localhost", port = 5432)


dbSendQuery(con, "DROP TABLE IF EXISTS obitos_brasil_sim.escolaridade CASCADE;")
dbSendQuery(con, "DROP TABLE IF EXISTS obitos_brasil_sim.estado_civil CASCADE;")

dbGetQuery(con, "CREATE TABLE obitos_brasil_sim.escolaridade(
                  ESC integer,
                  ESC_NIVEL varchar);")
dbGetQuery(con, "CREATE INDEX escolaridade_esc
           ON obitos_brasil_sim.escolaridade
           USING btree (esc);")

dbGetQuery(con, "COPY obitos_brasil_sim.escolaridade(
                  ESC, ESC_NIVEL)
                  FROM 'C:\\InfraServer\\Backup\\DadosTratamento\\escolaridade_temp.csv'
                  WITH (FORMAT csv, HEADER, DELIMITER ',', NULL 'NA');")


# Criar a tabela no banco de dados
dbGetQuery(con, "CREATE TABLE obitos_brasil_sim.estado_civil(
                  ESTCIV integer,
                  ESTCIV_NIVEL varchar);")
# Configurar a couna de index
dbGetQuery(con, "CREATE INDEX estado_civil_estciv
           ON obitos_brasil_sim.estado_civil
           USING btree (ESTCIV);")

# Inserir os dados no BD
dbGetQuery(con, "COPY obitos_brasil_sim.estado_civil(
                  ESTCIV, ESTCIV_NIVEL)
                  FROM 'C:\\InfraServer\\Backup\\DadosTratamento\\estacv_temp.csv'
                  WITH (FORMAT csv, HEADER, DELIMITER ',', NULL 'NA');")

# Apagar os dados temporários
file.remove('C:\\InfraServer\\Backup\\DadosTratamento\\escolaridade_temp.csv')
file.remove('C:\\InfraServer\\Backup\\DadosTratamento\\estacv_temp.csv')

# Desconectar do BD
dbDisconnect(con)

3. Seleção dos dados (SELECT)

Nesta página os dados são selecionados do banco de dados de acordo com as relações entre as tabelas. A query de seleção foi copiada para um arquivo .csv que será utilziado para realizar as análises.

# Configura a conexão com o BD
drv <- dbDriver("PostgreSQL")
con <- dbConnect(drv, db = "postgres", user = "postgres", password = "postgres123", host = "localhost", port = 5432)

# Executar a query para obter os dados do BD

dados_obitos <- dbGetQuery(con, "COPY (SELECT
DTOBITO,
DTNASC,
ESC_NIVEL,
ESTCIV_NIVEL,
HORAOBITO,
SEXO,
CODIDADE,
VALIDADE
FROM obitos_brasil_sim.estado_civil, obitos_brasil_sim.obitos, obitos_brasil_sim.escolaridade
WHERE estado_civil.ESTCIV = obitos.ESTCIV AND escolaridade.ESC = obitos.ESC) TO 
'C:\\InfraServer\\Backup\\DadosTratamento\\select_temp.csv' 
WITH CSV DELIMITER ',' HEADER;")

dbDisconnect(con)

Carregar o arquivo dos dados selecionados e vizualizar as primeiras linhas dos dados.

dados <- read.csv('C:\\InfraServer\\Backup\\DadosTratamento\\select_temp.csv')
dados$dtobito <- as.Date(dados$dtobito)
dados$dtnasc <- as.Date(dados$dtnasc)
dados$sexo <- ifelse(dados$sexo == 1, "Masculino", ifelse(dados$sexo == 2, "Feminino", "Indefinido"))

dados$idade_anos <- ifelse(dados$codidade < 4, 0, 
                           ifelse(dados$codidade == 4, dados$validade,
                                  ifelse(dados$codidade == 5, 100, NA)))

4. Códigos das vizualizaçoes

A exploração dos dados consiste em resumir os dados através de sumarios numéricos e visualizações gráficas. Esta sessão contém somente os códigos das figuras e dos resultados númericos obtidos, que serão apresentados na sessão de resultados.

Organização dos dados para a figura 1

# Sumariza os dados para os gráficos
resumo <- dados %>% group_by(sexo) %>% summarise(numero_mortes = length(sexo), idade = boxplot.stats(idade_anos)$stats)
resumo$legenda <- ifelse(resumo$idade == 100, "100+", resumo$idade)
resumo_geral <- dados %>% summarise(idade = boxplot.stats(idade_anos)$stats)
resumo_geral$legenda <- ifelse(resumo_geral$idade == 100, "100+", resumo_geral$idade)

resumo_mais_100 <- dados[dados$codidade == 5,] %>% group_by(sexo) %>% summarise(numero = length(sexo))


medias <- dados %>% group_by(sexo) %>% summarise(media = mean(idade_anos, na.rm = T))
media_idade <- mean(dados$idade_anos, na.rm = T)
resumo_idade <- dados %>% 
   group_by(sexo) %>% 
   summarise(numero_mortes = length(sexo), proporcao = paste0(round((length(sexo)/nrow(dados))*100, 2), "%"))

resumo_escolaridade <- dados %>% 
  group_by(esc_nivel, sexo) %>% 
  summarise(numero = length(esc_nivel), idade_media = round(mean(idade_anos, na.rm = T),2)) %>% filter(sexo != "Indefinido")

Código da figura 1.

# Plots que farão parte da figura
 g1 <- ggplot(dados, aes(x = sexo, y = idade_anos, fill = sexo)) + 
        geom_boxplot() +
        geom_text(data = resumo, aes(x = sexo, y = idade, label = legenda), position = position_dodge(1), vjust = 1) +
        geom_point(data = medias, aes(x = sexo, y = media), col = "red") +
        geom_text(data = medias, aes(x = sexo, y = media, label = round(media, 0)), col = "red", vjust = 1.2) +
          scale_fill_viridis(discrete = T, alpha = 0.5, begin = 0.4) +
          theme_ipsum() +
          theme(
            legend.position="none",
            plot.title = element_text(size=11)
          ) +
          ggtitle("Resumo das idades dos óbitos e diferênça entre sexos") +
          xlab("") +
          ylab("Idade (anos)")

 g2 <- ggplot(dados, aes(x = "Geral", y = idade_anos, fill = "")) + 
   geom_boxplot() + 
   geom_text(data = resumo_geral, aes(x = "Geral", y = idade, label = legenda), position = position_dodge(1), vjust = 1) +
   scale_fill_viridis(discrete = T, alpha = 0.5, begin = 0.8) +
   theme_ipsum(grid = F, axis = F) +
   theme(
            legend.position="none",
            plot.title = element_text(size=11),
            axis.text.y = element_blank()
          ) +
   ggtitle("Geral") +
   ylab("") +
   xlab("")
   

g3 <- ggplot(resumo_idade, aes(x= sexo, y = numero_mortes, fill = sexo)) + 
          geom_bar(stat = "identity") + 
          geom_text(aes(label = proporcao), vjust = 1.2) + 
          geom_text(aes(x = "Indefinido", y = numero_mortes[2], label = proporcao[2]), vjust = -1) + 
          scale_fill_viridis(discrete = T, alpha = 0.5, begin = 0.4) +
           theme_ipsum(grid = F, axis = F) +
           theme(
                    legend.position="none",
                    plot.title = element_text(size=11),
                    axis.text.y = element_blank()
                  ) +
           ggtitle("") +
           ylab("") +
           xlab("")


 g4 <- ggplot() +
   geom_text(aes(x = 1, y = 1, label = paste0("Total:\n", format(nrow(dados), big.mark = "."))), size = 8) +
   theme_transparent()
 
 figura1 <- ggarrange(ggarrange(g4, g3, ncol = 2, widths = c(0.7,2)),
            ggarrange(g1, g2, ncol = 2, widths = c(2,0.7)),
            nrow = 2, heights = c(1,2))
 figura1 <- annotate_figure(figura1,
                 top = text_grob("Resumos das informações de idade e sexo dos óbitos no Brasil entre 2015 e 2018", size = 12, face = "bold"))

Organização dos dados e código da figura 2.

dados$ano <- year(dados$dtobito)
dados$mes <- month(dados$dtobito)
dados$anomes <- paste(dados$ano, str_pad(dados$mes, 2, pad = "0"), sep = "_")

resumo_ano_mes <- dados %>% group_by(anomes) %>% summarise(numero = length(mes))
resumo_ano_mes$fator <- as.numeric(as.factor(resumo_ano_mes$anomes))
resumo_ano_mes$ano <- str_sub(resumo_ano_mes$anomes, start = 1,end = 4)
resumo_ano_mes$mes <- str_sub(resumo_ano_mes$anomes, start = 6)
resumo_ano_mes$mes <- month(as.numeric(resumo_ano_mes$mes), label = T, locale = "Portuguese_Brazil.1252")
meses_mais <- resumo_ano_mes %>% group_by(ano) %>% top_n(1, numero)
meses_menos <- resumo_ano_mes %>% group_by(ano) %>% top_n(-1, numero)


figura2 <- ggplot(resumo_ano_mes, aes(x = fator, y = numero, group = ano)) +
              geom_line() +
              geom_point(data = meses_mais, aes(x = fator, y = numero), col = "red") +
              geom_text(data = meses_mais, aes(x = fator, y = numero, label = mes), col = "red", vjust = -0.5) +
              geom_point(data = meses_menos, aes(x = fator, y = numero), col = "blue") +
              geom_text(data = meses_menos, aes(x = fator, y = numero, label = mes), col = "blue", vjust = 1) +
              scale_x_continuous(breaks = resumo_ano_mes$fator, labels = resumo_ano_mes$mes) +
              scale_y_continuous(n.breaks = 10) +
              facet_grid(cols = vars(ano), scales = "free", space = "free") +
              theme_few() +
              theme(panel.spacing = unit(0, "lines"),
                    panel.border = element_rect(color = alpha("black", alpha = 0.05)),
                    strip.background = element_rect(colour = alpha("black", alpha = 0.05), fill = alpha("black", alpha = 0.05)),
                    strip.text = element_text(size = 12)) +
              xlab("Mês") +
              ylab("Número de mortos")

5. Resultados

Foram registrados um total de 4610125 mortes no Brasil entre os anos de 2015 a 2018. Deste total 55.97% são pessoas do sexo masculino. A idade média geral de sobrevivência foi de 66.59 anos, sendo que os homens viveram em média até os 62.73 anos e as mulheres até os 71.48 anos. 50% das pessoas viveram entre 55 e 82 anos. O resumo das informações está apresentado gráficamente na Figura 1. O número de homens que sobreviveu por mais de 100 anos foi de 10449 e de mulheres foi de 24508.

Figura 1. Resumo das informações de sexo e idade das pessoas que morreram no Brasil entre 2015 e 2018.

O número de mortes teve variação mensal ao longo dos anos, porém foi possível encontrar um padrão nos números de mortes mensais ao longo dos anos. Os mês de fevereiro, em 3 dos 4 anos observados foi o mês que foi registrado o menos número de óbitos, já o mês de julho foi o mês que apresentou o maior número de óbitos também em 3 dos 4 anos observados (Figura 2).

Figura 2. Resumo das informações das mortes no Brasil entre os anos de 2015 e 2018. Foram destacados os meses que apresentaram os maiores e os menores números de mortes em cada ano.

Quanto ao número de anos de formação, o maior número de óbitos registrados é para pessoas que estudaram ente 1 e 7 anos. As pessoas que estudaram de 8 a 11 anos estão abaixo da média de idade de sobrevivênvia, tanto para homens quanto para mulheres. As mulheres sem nenhum registro de estudo foram as pessoas que apresentaram a maior idade média do óbito.

Tabela 1. Dados de níveis de anos de estudo, número de óbitos e idade média, divididos por sexo.
Anos de estudo Sexo Número de óbitos Idade média
1 a 3 anos Feminino 537772 74.07
1 a 3 anos Masculino 657443 66.38
2 anos e mais Feminino 101995 63.22
2 anos e mais Masculino 142179 64.02
4 a 7 anos Feminino 403367 68.37
4 a 7 anos Masculino 628636 58.09
8 a 11 anos Feminino 271290 62.59
8 a 11 anos Masculino 423775 55.15
Ignorado Feminino 260199 71.97
Ignorado Masculino 346638 62.68
Nenhuma Feminino 454446 78.07
Nenhuma Masculino 381632 72.09

Obs. As observações feitas a respeito dos dados são apenas para treinamento e não devem ser consideradas para tomadas de decisão e como dados oficiais.

.