Fluxo ETL: SINASC

A documentação a seguir apresenta o processo ETL (extract, transform, load) aplicado aos dados do Sistema de Informações sobre Nascimentos (SINASC) do DATASUS para indexação na Plataforma de Ciência de Dados aplicada à Saúde (PCDaS). O processo ETL aplicado consiste basicamente em:

Extract:

  • Acessar o servidor FTP do DATASUS e baixar os arquivos com extensão .dbc contendo os microdados anônimos do SINASC para cada estado e para cada ano disponível/desejado;
  • Converter os arquivos baixados para a extensão .dbf;
  • Ler e unir os arquivos em um único conjunto de dados para posterior tratamento.

Transform:

  • Tratar o conjunto de dados adquirido de maneira a:
    • Eliminar valores inválidos;
    • Decodificar e enriquecer os dados de acordo com dicionário de dados do SINASC;
    • Enriquecer os dados relacionados a município;
    • Enriquecer os dados relacionados a UF;
    • Enriquecer os dados relacionados a Classificação Estatística Internacional de Doenças e Problemas Relacionados com a Saúde (CID10);
    • Enriquecer os dados relacionados a data e idade;
    • Enriquecer os dados relacionados a coordenadas;
    • Enriquecer os dados relacionados a partos prematuros.

Load:

  • Indexar dados tratados do SINASC em banco de dados NoSQL Elasticsearch localizado em infraestrutura da PCDaS no Laboratório Nacional de Computação Científica (LNCC);
  • Coletar log de indexação.

A implementação de todo o fluxo ETL descrito foi feita no ambiente da ferramenta Dataiku Data Science Studio (DSS). Este processo ETL é reexecutado para cada ano selecionado disponível no servidor FTP do DATASUS. Uma visão geral do fluxo ETL é apresentada no diagrama a seguir:

            Fase Extract                                      Fase Transform                                      Fase Load

Detalhes de código/dados da implementação do fluxo ETL são apresentados a seguir.


Fase Extract:

1: Acessando o servidor FTP do DATASUS e baixando os arquivos com extensão .dbc contendo os dados do SINASC para cada estado e para cada ano disponível/desejado;

Código R:
Função para fazer download de arquivos .dbc do SINASC a partir do FTP do Datasus:
download.dbc <- function(ftp_path,
                         dest_files_path = getwd(),
                         estados = NULL, anos = NULL){
  require(RCurl)
  require(tidyverse)
  
  url <- ftp_path
  #userpwd <- "yourUser:yourPass"
  #recupera o nome dos arquivos em ftp_path
  filenames <- getURL(url, userpwd = NULL,
                      ftp.use.epsv = FALSE,dirlistonly = TRUE)
  filenames <- unlist(strsplit(filenames,"\n"))
  filenames <- data.frame(filename=filenames)
  filenames <- data.frame(lapply(filenames, as.character), stringsAsFactors=FALSE)
  
  #filtra os estados desejados se estes forem especificados
  if(!is.null(estados)){
    filenames <- filenames %>%
      filter(str_detect(filename, paste(estados,sep="",collapse = '|')))
  }
  #filtra os anos desejados se estes forem especificados
  if(!is.null(anos)){
    filenames <- filenames %>%
      filter(str_detect(filename, paste(anos,sep="",collapse = '|')))
  }
  
  #faz download dos arquivos selecionados e salva os arquivos em dest_files_path
  for (filename in filenames$filename) {
    download.file(paste(url, filename, sep = ""), paste(dest_files_path, "/", filename, sep = ""))
  }
  
  #retorna um data.frame com os nomes e caminho dos arquivos
  return(data.frame(file_name=filenames$filename,file_path=dest_files_path))
}
Código para fazer download de arquivos .dbc do SINASC a partir do FTP do Datasus:
#============[INTERAÇÂO DSS]============
library(dataiku)
library(dplyr)
#===========================================

#Caminho para função "download.dbc"
path.script = "https://github.com/bigdata-icict/ETL-Dataiku-DSS/download.dbc.r"

#Caminho FTP Datasus
ftp_path = "ftp://ftp.datasus.gov.br/dissemin/publicos/SINASC/NOV/DNRES/"

#============[EDITAR]============
#Local para salvamento dos arquivos .dbc
path.data = "path_dbc_files"
#================================

#============[OPCIONAL]============
#filtros de estado e/ou anos
estados = NULL #outro exemplo: c("RJ")
anos = 2016 #outro exemplo: 2000:2014
#==================================

#Carrega função "download.dbc"
if(!exists("download.dbc", mode="function")) source(path.script)

# Computa retorno da receita: nome dos arquivos .dbc baixados
datasus_files_list <- download.dbc(ftp_path = ftp_path,
                                       dest_files_path = path.data,
                                       estados = estados,
                                       anos = anos)

#============[INTERAÇÂO DSS]============ -> Alternativa: salvar data.frame em arquivo .csv 
# Retornando resultados para dataset do DSS
dkuWriteDataset(datasus_files_list,"datasus",schema = TRUE)
#===========================================
Retorno (exemplo):

2: Convertendo os arquivos baixados para a extensão .dbf e então lendo e unindo os arquivos em um único conjunto de dados no DSS para posterior tratamento.

Código R:
Função para converter, ler e unir os arquivos de dados do SINASC:
load.dbc <- function(files){
  require(read.dbc)
  
  df_from_DBC = data.frame()
  
  for(f in files){
    bind_rows( df_from_DBC, read.dbc(f) ) -> df_from_DBC
  }
  
  return(df_from_DBC)
}
Código para converter, ler e unir arquivos de dados do SINASC e escrever conjunto de dados resultantes no DSS:
#============[INTERAÇÂO DSS]============
library(dataiku)
library(dplyr)
#===========================================

#Instala o pacote "read.dbc"
#install.packages("read.dbc") 

#Caminho para função "load.dbc.sim"
path.script = "https://github.com/bigdata-icict/ETL-Dataiku-DSS/load.dbc.r"

#Carrega função "load.dbc"
if(!exists("load.dbc", mode="function")) source(path.script)

#============[INTERAÇÂO DSS]============  -> Alternativa: leitura de data.frame a partir de arquivo .csv
#Acessa lista de arquivos baixados para posterior conversão e leitura 
datasus_files_list <- dkuReadDataset("datasus")
#===========================================

#Concatena caminhos e nomes dos arquivos
datasus_files_list <- paste(datasus_files_list$file_path,datasus_files_list$file_name,sep="")

# Computa retorno da receita: dados do SINASC advindos de todos os arquivos .dbc baixados
df_from_DBC <- load.dbc(datasus_files_list)

#============[INTERAÇÂO DSS]============ -> Alternativa: salvar data.frame em arquivo .csv
# Retornando resultados para dataset do DSS
dkuWriteDataset(df_from_DBC, "DNRES",schema = TRUE)
#===========================================
Retorno (exemplo):


Fase Transform:

A transformação/preparação dos dados foi feita utilizando-se funcionalidades (processors) disponíveis no ambiente da ferramenta Dataiku Data Science Studio (DSS). A receita ("recipe") utilizada está disponível para download/visualização através dos arquivos json:

prepare_DNRES.json e prepare_DNRES.shaker

Alguns detalhes do tratamento dos dados são apresentados a seguir, onde colunas com nomes em maiúsculo representam dados originais advindos do DATASUS e colunas com nomes em minúsculo representam dados resultantes de tratamento:

1: Eliminando valores inválidos:

Coluna Valores aceitos Valores inválidos são substituídos por
PARTO [1,2,9] [9]
SEXO [0,1,2,'M','F'] [0]
RACACOR [1,2,3,4,5] [9]
ESTCIVMAE [1,2,3,4,5,9] [9]
ESCMAE [1,2,3,4,5,9] [9]
LOCNASC [1,2,3,4,9] [9]
IDANOMAL [1,2,9] [9]
GRAVIDEZ [1,2,3,9] [9]
GESTACAO [1,2,3,4,5,6,9] [9]
CONSULTAS [1,2,3,4,9] [9]
PESO números inteiros []
IDADEMAE números inteiros []
CODOCUPMAE números inteiros []
QTDFILVIVO números inteiros []
QTDFILMORT números inteiros []

2: Decodificando e enriquecendo os dados:

Coluna Códigos Coluna resultante
SEXO {'M':1, 'F':2} SEXO
SEXO {0:"Ignorado",1:"Masculino", 2:"Feminino"} def_sexo
RACACOR {1:"Branca",2:"Preta",3:"Amarela",4:"Parda",5:"Indígena", 9:"Ignorado"} def_raca_cor
ESTCIVMAE {1:"Solteiro", 2:"Casado", 3:"Viúvo",4:"Separado Judic./Divorciado",5:"União consensual",9:"Ignorado"} def_est_civil
LOCNASC {9:"Ignorado",1:"Hospital",2:"Outro Estab. Saúde", 3:"Domicílio", 4:"Outros"} def_loc_nasc
ESCMAE {1:"Nenhuma",2:"1 a 3 anos",3:"4 a 7 anos",4:"8 a 11 anos",5:"12 e mais",9:"Ignorado"} def_escol_mae
GRAVIDEZ {9:'Ignorado', 1:'Única',2:'Dupla',3:'Tripla ou mais'} def_gravidez
GESTACAO {1:'Menos de 22 semanas', 2:'22 a 27 semanas', 3:'28 a 31 semanas', 4:'32 a 36 semanas', 5:'37 a 41 semanas', 6:'42 semanas e mais', 9:'Ignorado'} def_gestacao
PARTO {9:"Ignorado",1:"Vaginal",2:"Cesáreo"} def_parto
CONSULTAS {9:'Ignorado', 1:'Nenhuma',2:'de 1 a 3', 3:'de 4 a 6',4:'7 e mais'} def_consultas
IDANOMAL {9:'Ignorado', 1:'Sim',2:'Não'} def_anomalia

3: Enriquecendo os dados relacionados a município:

O enriquecimento dos dados do SIM relacionados a município foram baseados nos dados disponíveis no seguinte arquivo:

Dados - Município

Coluna base Operação Colunas resultantes
CODMUNRES Truncar para um máximo de 6 caracteres cod_mun_res
cod_mun_res Fazer junção ("left join") com base na coluna 'MUNCOD' em 'municipios' ["res_MUNCOD", "res_MUNNOME", "res_MUNNOMEX", "res_AMAZONIA", "res_FRONTEIRA", "res_CAPITAL", "res_UFCOD", "res_MSAUDCOD", "res_RSAUDCOD", "res_CSAUDCOD", "res_LATITUDE", "res_LONGITUDE", "res_ALTITUDE", "res_AREA", "res_codigo_adotado"]
CODMUNNASC Truncar para um máximo de 6 caracteres cod_mun_nasc
cod_mun_nasc Fazer junção ("left join") com base na coluna 'MUNCOD' em 'municipios' ["nasc_MUNCOD", "nasc_MUNNOME", "nasc_MUNNOMEX", "nasc_AMAZONIA", "nasc_FRONTEIRA", "nasc_CAPITAL", "nasc_UFCOD", "nasc_MSAUDCOD", "nasc_RSAUDCOD", "nasc_CSAUDCOD", "nasc_LATITUDE", "nasc_LONGITUDE", "nasc_ALTITUDE", "nasc_AREA", "nasc_codigo_adotado"]

4: Enriquecendo os dados relacionados a UF:

O enriquecimento dos dados do SIM relacionados a UF foram baseados nos dados disponíveis no seguinte arquivo:

Dados - UF

Coluna base Operação Colunas resultantes
res_UFCOD Fazer junção ("left join") com base na coluna 'CODIGO' em 'ufs' ["res_SIGLA_UF", "res_CODIGO_UF", "res_NOME_UF"]
res_CODIGO_UF Definir a região da UF de acordo com o primeiro dígito de seu código {1:'Norte', 2:'Nordeste', 3:'Sudeste', 4:'Sul', 5:'Centro-Oeste'} res_REGIAO
nasc_UFCOD Fazer junção ("left join") com base na coluna 'CODIGO' em 'ufs' ["nasc_SIGLA_UF", "nasc_CODIGO_UF", "nasc_NOME_UF"]
nasc_CODIGO_UF Definir a região da UF de acordo com o primeiro dígito de seu código {1:'Norte', 2:'Nordeste', 3:'Sudeste', 4:'Sul', 5:'Centro-Oeste'} nasc_REGIAO

5: Enriquecendo os dados relacionados a CID 10:

O enriquecimento dos dados do SIM relacionados a CID10 foram baseados nos dados disponíveis nos seguintes arquivos:

CID10 - Capítulos, CID10 - Grupos, CID10 - Categorias, CID10 - Subcategorias

Coluna base Operação Colunas resultantes
CODANOMAL Truncar para um máximo de 3 caracteres CODANOMAL_tmp_1
CODANOMAL Truncar para um máximo de 4 caracteres CODANOMAL_tmp_2
CODANOMAL_tmp_1 Fazer junção ("left join") com base na coluna 'codigo' em 'cid10_capitulos' e extração da coluna 'descricao_breve' codanomal_capitulo
CODANOMAL_tmp_1 Fazer junção ("left join") com base na coluna 'codigo' em 'cid10_grupos' e extração da coluna 'descricao_breve' codanomal_grupo
CODANOMAL_tmp_1 Fazer junção ("left join") com base na coluna 'CAT' em 'cid10_categorias' e extração da coluna 'DESCRABREV' codanomal_categoria
CODANOMAL_tmp_2 Fazer junção ("left join") com base na coluna 'SUBCAT' em 'cid10_subcategorias' e extração da coluna 'DESCRABREV' codanomal_subcategoria
CODANOMAL_tmp_1 e CODANOMAL_tmp_2 Remoção de colunas []

6: Enriquecendo os dados relacionados a data e idade:

Coluna base Operação Coluna resultante
DTNASC Converter para tipo data data_nasc
data_nasc Extrair ano (se 1996 <= ano <= 2016) ano_nasc
data_nasc Extrair dia da semana dia_semana_nasc

7: Enriquecendo os dados relacionados a coordenadas:

Coluna base Operação Coluna resultante
res_LATITUDE e res_LONGITUDE Concatenar coordenadas res_coordenadas
nasc_LATITUDE e nasc_LONGITUDE Concatenar coordenadas nasc_coordenadas

8: Enriquecendo os dados relacionados a partos prematuros:

Coluna base Operação Coluna resultante
GESTACAO e PESO Indicar a prematuridade do nascimento com os códigos 0: não há indícios de prematuridade; 1: há indício de prematuridade dado pela idade gestacional ('GESTACAO'<=4); 2: há indício de prematuridade dado pelo peso ao nascer ('PESO'<2500); 3: a idade gestacional e o peso ao nascer indicam prematuridade parto_prematuro
parto_prematuro Definir parto de acordo com código {0:'Termo', 1:'Inconclusivo-IG', 2:'Inconclusivo-Peso', 3:'Prematuro'} def_parto_prematuro

Retorno da fase de tratamento (exemplo):


Fase Load:

1: Indexando dados tratados do SINASC em banco de dados NoSQL Elasticsearch:

Uma vez finalizada a trasformação/preparação dos dados, estes são indexados em um servidor de banco de dados NoSQL Elasticsearch localizado em infraestrutura da PCDaS no LNCC.

Código Python:
O código utilizado para indexação está disponível em formato Jupyter Notebook: Notebook Python
Retorno - log de indexação (exemplo):


Dados e dicionário de variáveis - SINASC:

O download e a prévia do conjunto de dados resultante de todo o tratamento realizado e indexado no Elasticsearch estão disponíveis na PCDaS, assim como o Dicionário de variáveis.


Dashboards Kibana:

Os dados SINASC indexados no Elasticsearch possibilitam o desenvovimento de dashboards Kibana para a visualização simples, rápida e dinâmica de grandes quantidades de dados. Os dashboards desenvolvidos estão disponíveis para visualização na PCDaS na seção de Análise visual.

You can’t perform that action at this time.