Concatenando data.frames

Linux
R
DATASUS

Como juntar os diversos arquivos .dbc do DATASUS em um data.frame; comparação de tempos de processamento e bibliotecas.

Autor

Mario O. de Menezes

Data de Publicação

1 de outubro de 2020

Introdução

O DATASUS, braço tecnológico do Ministério da Saúde, disponibiliza uma vasta quantidade de informações sobre diversos aspectos do Serviço Unificado de Saúde (SUS). Muitos destes arquivos são disponibilizados em um formato dbc, que é um “compressed DBF”.

Estes arquivos são disponibilizados no site de FTP do DATASUS. Para fins deste pequeno experimento, todos os arquivos foram baixados e estão na máquina local.

O objetivo deste pequeno estudo é verificar os tempos gastos em cada etapa: leitura dos arquivos, filtros e seleção de variáveis, e a transformação em um data.frame para posterior manipulação.

Carregando as bibliotecas

#| label: bibliotecas
library(tidyverse)
library(read.dbc)
library(data.table)
library(microbenchmark)

Listando todos os arquivos das APACS no diretório

Todos os arquivos das APACs foram baixados do site FTP do DATASUS.

#| label: ftpdir
diretorio <- "/datahome/datasets/datasus.gov.br/SIASUS/PA-LaudosDiversos/"

Selecionando 4 arquivos, 2 de cada estado, de Minas Gerais e Rio de Janeiro

#| label: mgrj
PREF <- "PA"
# indique o estado ou "" para todos os estados
UF <- "(MG|RJ)" 
MESES <- "12"
ANO <- "(18|19)"
#| label: mgrjarqs
arquivos <- list.files(diretorio, paste0(PREF,UF,ANO,MESES,".*.dbc"))

Variáveis selecionadas

#| label: varstokeep
vars_to_keep = c("PA_CODUNI","PA_UFMUN","PA_TPUPS","PA_TIPPRE", "PA_CNPJCPF",  "PA_MVM","PA_CMP","PA_PROC_ID","PA_CNSMED","PA_MOTSAI","PA_OBITO","PA_CIDPRI", "PA_CIDSEC","PA_CIDCAS","PA_CATEND","PA_IDADE","PA_SEXO","PA_RACACOR","PA_MUNPCN", "PA_UFDIF","PA_MNDIF","PA_ETNIA")

Tempo de leitura dos arquivos (em segundos)

#| label: readingmgrj
timeMGRJ4arqs <- system.time({f1 <- read.dbc(paste0(diretorio,arquivos[1])); 
f2 <- read.dbc(paste0(diretorio,arquivos[2])); 
f3 <- read.dbc(paste0(diretorio,arquivos[3])); 
f4 <- read.dbc(paste0(diretorio,arquivos[4]));})
timeMGRJ4arqs
    user   system   elapsed
  82.165   16.305    98.629

Montando uma lista de data.frames

Para estes 4 arquivos iniciais, vou fazer o processo de montar a lista e concatenar usando as duas bibliotecas data.table e dplyr para comparar o tempo nesta etapa.

Cada data.frame inicial é filtrado e as variáveis são selecionadas; são colocados em uma lista de data.frames para a concatenação posterior.

Usando o data.table

#| label: listmgrj
apacsdt <- list()
timeMGRJ4arqs_tolistdt <- system.time({
  # f1
  f1 <- setDT(f1)
  f1 <-
    f1[(PA_PROC_ID == "0204030030" |
          PA_PROC_ID == "0204030188") &
         PA_SEXO == "F", ..vars_to_keep]
  estado <- substr(arquivos[1], 3, 4)
  ano <- substr(arquivos[1], 5, 6)
  mes <- substr(arquivos[1], 7, 8)
  ano <- as.numeric(paste0("20", ano))
  f1[, `:=`(ESTADO = estado,
            ANO = ano,
            MES = mes)]
  apacsdt  <- append(apacsdt, list(f1))
  
  #f2
  f2 <- setDT(f2)
  f2 <-
    f2[(PA_PROC_ID == "0204030030" |
          PA_PROC_ID == "0204030188") &
         PA_SEXO == "F", ..vars_to_keep]
  estado <- substr(arquivos[2], 3, 4)
  ano <- substr(arquivos[2], 5, 6)
  mes <- substr(arquivos[2], 7, 8)
  ano <- as.numeric(paste0("20", ano))
  f2[, `:=`(ESTADO = estado,
            ANO = ano,
            MES = mes)]
  apacsdt  <- append(apacsdt, list(f2))
  
  # f3
  f3 <- setDT(f3)
  f3 <-
    f3[(PA_PROC_ID == "0204030030" |
          PA_PROC_ID == "0204030188") &
         PA_SEXO == "F", ..vars_to_keep]
  estado <- substr(arquivos[3], 3, 4)
  ano <- substr(arquivos[3], 5, 6)
  mes <- substr(arquivos[3], 7, 8)
  ano <- as.numeric(paste0("20", ano))
  f3[, `:=`(ESTADO = estado,
            ANO = ano,
            MES = mes)]
  apacsdt  <- append(apacsdt, list(f3))
  
  # f4
  f4 <- setDT(f4)
  f4 <-
    f4[(PA_PROC_ID == "0204030030" |
          PA_PROC_ID == "0204030188") &
         PA_SEXO == "F", ..vars_to_keep]
  estado <- substr(arquivos[4], 3, 4)
  ano <- substr(arquivos[4], 5, 6)
  mes <- substr(arquivos[4], 7, 8)
  ano <- as.numeric(paste0("20", ano))
  f4[, `:=`(ESTADO = estado,
            ANO = ano,
            MES = mes)]
  apacsdt  <- append(apacsdt, list(f4))
  
})
timeMGRJ4arqs_tolistdt
  user   system   elapsed
 0.597    0.000     0.133

Usando o dplyr

#| label: listmgrjdplyr
apacs <- list()
timeMGRJ4arqs_tolistdplyr <- system.time({
  # f1
  f1 <- f1 %>% filter((PA_PROC_ID == "0204030030" |
          PA_PROC_ID == "0204030188") &
         PA_SEXO == "F") %>%
    select(all_of(vars_to_keep))
  estado <- substr(arquivos[1], 3, 4)
  ano <- substr(arquivos[1], 5, 6)
  mes <- substr(arquivos[1], 7, 8)
  ano <- as.numeric(paste0("20", ano))
  f1 <- f1 %>% mutate(ESTADO=estado,ANO=ano,MES=mes)
  apacs  <- append(apacs, list(f1))
  
  #f2
  f2 <- f2 %>% filter((PA_PROC_ID == "0204030030" |
          PA_PROC_ID == "0204030188") &
         PA_SEXO == "F") %>%
    select(all_of(vars_to_keep))
  estado <- substr(arquivos[2], 3, 4)
  ano <- substr(arquivos[2], 5, 6)
  mes <- substr(arquivos[2], 7, 8)
  ano <- as.numeric(paste0("20", ano))
  f2 <- f2  %>% mutate(ESTADO=estado,ANO=ano,MES=mes)
  apacs  <- append(apacs, list(f2))
  
  # f3
  f3 <- f3 %>% filter((PA_PROC_ID == "0204030030" |
          PA_PROC_ID == "0204030188") &
         PA_SEXO == "F") %>%
    select(all_of(vars_to_keep))
  estado <- substr(arquivos[3], 3, 4)
  ano <- substr(arquivos[3], 5, 6)
  mes <- substr(arquivos[3], 7, 8)
  ano <- as.numeric(paste0("20", ano))
  f3 <- f3 %>% mutate(ESTADO=estado,ANO=ano,MES=mes)
  apacs  <- append(apacs, list(f3))
  
  # f4
  f4 <- f4 %>% filter((PA_PROC_ID == "0204030030" |
          PA_PROC_ID == "0204030188") &
         PA_SEXO == "F") %>%
    select(all_of(vars_to_keep))
  estado <- substr(arquivos[4], 3, 4)
  ano <- substr(arquivos[4], 5, 6)
  mes <- substr(arquivos[4], 7, 8)
  ano <- as.numeric(paste0("20", ano))
  f4 <- f4 %>% mutate(ESTADO=estado,ANO=ano,MES=mes)
  apacs  <- append(apacs, list(f4))
  
})
timeMGRJ4arqs_tolistdplyr
   user   system  elapsed
 0.099     0.002    0.107

Concatenando os data.frames

Com a função rbindlist do pacote data.table

#| label: dfdtmgrj
timeMGRJ4arqs_todf <- system.time({
X <-
  data.table::rbindlist(apacsdt) 
assign("APACSPA_MGRJdt", X)
rm(X)
})
timeMGRJ4arqs_todf
  user    system  elapsed
  0.07     0.000    0.008

Com a função bind_rows do pacote dplyr

#| label: dfdplyrmgrj
timeMGRJ4arqs_tolistdplyr <- system.time({
  X <-
   bind_rows(apacs)
assign("APACSPA_MGRJdplyr", X)
rm(X)
})
timeMGRJ4arqs_tolistdplyr
  user    system  elapsed
 0.029     0.000    0.029

Selecionando 4 arquivos de São Paulo

#| label: sp
PREF <- "PA"
# indique o estado ou "" para todos os estados
UF <- "SP" 
MESES <- "(01|02)"
ANO <- "19"
#| label: sparqs
arquivos <- list.files(diretorio, paste0(PREF,UF,ANO,MESES,".*.dbc"))

Tempo de leitura dos arquivos (em segundos)

#| label: readingsp
timeSP4arqs <- system.time({f1 <- read.dbc(paste0(diretorio,arquivos[1])); 
f2 <- read.dbc(paste0(diretorio,arquivos[2])); 
f3 <- read.dbc(paste0(diretorio,arquivos[3])); 
f4 <- read.dbc(paste0(diretorio,arquivos[4]));})
timeSP4arqs
     user    system   elapsed
  102.826    13.100   116.002

Montando a lista de data.frames

#| label: listsp
apacs <- list()
timeSP4arqs_tolist <- system.time({
  # f1
  f1 <- setDT(f1)
  f1 <-
    f1[(PA_PROC_ID == "0204030030" |
          PA_PROC_ID == "0204030188") &
         PA_SEXO == "F", ..vars_to_keep]
  estado <- substr(arquivos[1], 3, 4)
  ano <- substr(arquivos[1], 5, 6)
  mes <- substr(arquivos[1], 7, 8)
  ano <- as.numeric(paste0("20", ano))
  f1[, `:=`(ESTADO = estado,
            ANO = ano,
            MES = mes)]
  apacs  <- append(apacs, list(f1))
  
  # f2
  f2 <- setDT(f2)
  f2 <-
    f2[(PA_PROC_ID == "0204030030" |
          PA_PROC_ID == "0204030188") &
         PA_SEXO == "F", ..vars_to_keep]
  estado <- substr(arquivos[2], 3, 4)
  ano <- substr(arquivos[2], 5, 6)
  mes <- substr(arquivos[2], 7, 8)
  ano <- as.numeric(paste0("20", ano))
  f2[, `:=`(ESTADO = estado,
            ANO = ano,
            MES = mes)]
  apacs  <- append(apacs, list(f2))
  
  # f3
  f3 <- setDT(f3)
  f3 <-
    f3[(PA_PROC_ID == "0204030030" |
          PA_PROC_ID == "0204030188") &
         PA_SEXO == "F", ..vars_to_keep]
  estado <- substr(arquivos[3], 3, 4)
  ano <- substr(arquivos[3], 5, 6)
  mes <- substr(arquivos[3], 7, 8)
  ano <- as.numeric(paste0("20", ano))
  f3[, `:=`(ESTADO = estado,
            ANO = ano,
            MES = mes)]
  apacs  <- append(apacs, list(f3))
  
  # f4
  f4 <- setDT(f4)
  f4 <-
    f4[(PA_PROC_ID == "0204030030" |
          PA_PROC_ID == "0204030188") &
         PA_SEXO == "F", ..vars_to_keep]
  estado <- substr(arquivos[4], 3, 4)
  ano <- substr(arquivos[4], 5, 6)
  mes <- substr(arquivos[4], 7, 8)
  ano <- as.numeric(paste0("20", ano))
  f4[, `:=`(ESTADO = estado,
            ANO = ano,
            MES = mes)]
  apacs  <- append(apacs, list(f4))
  
})
timeSP4arqs_tolist
   user    system    elapsed
  0.841     0.000      0.143

Concatenando os data.frames

Com a função rbindlist do pacote data.table

#| label: dfdtsp
timeSP4arqs_todf <- system.time({
X <-
  data.table::rbindlist(apacs)
assign("APACSPA_SPdt", X)
rm(X)
})
timeSP4arqs_todf
   user     system    elapsed
  0.012      0.000      0.011

Com a função bind_rows do pacote dplyr

#| label: dfdplyrsp
timeSP4arqs_tolistdplyr <- system.time({
  X <-
   bind_rows(apacs)
assign("APACSPA_SPdplyr", X)
rm(X)
})
timeSP4arqs_tolistdplyr
   user    system    elapsed
  0.035     0.000      0.035

Gravando um CSV

Usando data.table - função fwrite

#| label: writecsvdt
caminho <- getwd()
nomearquivocsv <- "APACSSPdt.CSV"
system.time(fwrite(APACSPA_SPdt,paste(caminho,nomearquivocsv,sep="/")))
   user    system    elapsed
  0.768     0.029      0.108

Usando readr - função write_csv

#| label: writecsvdplyr
nomearquivocsv <- "APACSSPdplyr.CSV"
system.time(write_csv(APACSPA_SPdt,paste(caminho,nomearquivocsv,sep="/")))
   user    system    elapsed
  0.432     0.457      0.360