Tutoriais para utilização dos serviços tecnológicos da PCDaS | Plataforma de Ciência de Dados aplicada à Saúde

Acesse a Plataforma

Tutoriais para utilização dos serviços tecnológicos da PCDaS


Vídeos tutoriais para a interface Análise Visual


Análise Visual - Introdução


Análise Visual - Dashboards

 

 

Tutorial em R para acesso à interface tecnológica Mineração de Dados e Análise Preditiva

 

Tutorial para conexão aos dados da PCDaS via R

Este notebook oferece um tutorial para acesso aos dados indexados pela Plataforma de Ciência de Dados aplicada à Saúde (PCDaS) via R.

Utilizaremos, como exemplo, os dados do Sistema de Informações de Mortalidade (SIM) e iremos demonstrar como acessá-los através do R.

Os dados do SIM estão disponíveis em um índice do ElasticSearch (ES), que contém todos os registros individuais das declarações de óbito.

Pacotes necessários

Primeiro definimos uma função auxiliar para carregar os pacotes necessários à execução deste tutorial e instalar algum pacote caso este não esteja disponível.

loadlibrary <- function(x){
  if (!require(x,character.only = TRUE)) {
    install.packages(x, repos='http://cran.fiocruz.br/', dep=TRUE)
    if(!require(x,character.only = TRUE)) stop("Package not found")
  }
}

O acesso ao índice no ES é realizado através do pacote elasticsearchr.

loadlibrary("elasticsearchr")
Loading required package: elasticsearchr

Vamos também utilizar outras bibliotecas do R para facilitar a manipulação dos dados obtidos.

packages <- c("dplyr","curl","jsonlite","ggplot2")
lapply(packages, loadlibrary)
Loading required package: dplyr

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union

Loading required package: curl
Loading required package: jsonlite
Loading required package: ggplot2
  1. NULL
  2. NULL
  3. NULL
  4. NULL

Acesso ao ElasticSearch

O primeiro passo é informar ao R os parâmetros de conexão com o índice no ES.

Nos parâmetros es_user e es_pwd, informe o mesmo usuário e senha que você usar para acessar a plataforma.

es_host <- "dados-pcdas.icict.fiocruz.br"
es_port <- 443
es_transport_schema <- "https"
es_user <- "aluno.treinamento"
es_pwd <- "aluno123456"

#URL de conexão com o ES
es_url <- paste(es_transport_schema,"://",es_user,":",es_pwd,"@",es_host,":",es_port,sep="")

Em seguida, criamos um objeto para acesso ao índice do ES contendo os dados do SIM.

es_sim <- elasticsearchr::elastic(es_url, "datasus-sim-dss")

Outros índices também podem ser acessados da mesma forma. Para isso, basta fazer referência ao seu respectivo nome, como por exemplo "datasus-sinasc-dss" (referente ao Sistema de Informações de Nascidos Vivos (SINASC)).

Podemos testar a conexão pedindo algumas informações básicas sobre o ElasticSearch.

print(es_sim)
$search_url
[1] "https://aluno.treinamento:aluno123456@dados-pcdas.icict.fiocruz.br:443/datasus-sim-dss/_search"

$cluster_url
[1] "https://aluno.treinamento:aluno123456@dados-pcdas.icict.fiocruz.br:443"

$index
[1] "datasus-sim-dss"

$doc_type
NULL

attr(,"class")
[1] "elastic_rescource" "elastic"          

Fazendo buscas nos dados

Podemos executar buscas nos dados e ver os documentos (registros) do índice (banco do SIM) com o comando query e o operador %search%.

Com o comando query podemos definir qualquer tipo de busca que o ES permite usando-se a sua sintaxe JSON nativa. O operador %search% executa a busca definida, passando sua definição ao ES e retornando os resultados em um formato de tabela, ou, data.frame.

Por padrão, é retornado até os 10.000 primeiros resultados. Vamos ver mais a frente que dificilmente iremos precisar mais do que isso, pois iremos trabalhar com agregações.

Como exemplo, uma busca por todos os documentos e todos os campos que existem no índice pode ser definida da seguinte forma.

tudo <- query('{
                 "match_all": {}
               }')

Essa busca poderia então ser executada com o operador %search% aplicado ao nosso objeto de conexão com o índice SIM es_sim:

es_sim %search% tudo

Entretanto, como o número de documentos no índice do SIM é significativamente grande (22.366.860), uma busca como essa não é recomendada (por ser muito custosa computacionalmente) e muitas vezes pode ser desnecessária.

Neste caso, é geralmente mais interessante a especificação de apenas alguns campos, filtros e principalmente agregações que sejam relevantes para se obter a resposta desejada.

Iremos explorar esta possibilidade nos próximos passos.

Agregando resultados

Se quisermos gerar tabelas mais complexas de contagens, podemos usar uma forma específica para pedir agregações de resultados.

Por exemplo, quantas pessoas vieram a óbito por estado? Podemos obter este resultado especificando uma agregação.

Uma agregação para o ES precisa ser escrita seguindo um padrão. Veja abaixo:

agg_uf <- aggs('{
 "a1": {
   "terms": {
     "field": "res_SIGLA_UF",
     "size": 27
   }
 }
}')

Estamos criando um objeto chamado agg_uf no R, que será usado na consulta ao ES. O que significa cada linha desse objeto? * aggs: esse comando declara ao ES que você está requerindo uma agregação; * a1: nome da agregação, você pode modificar esse nome; * terms: isso declara ao ES que você quer fazer a agregação a partir de uma variável categórica, resultando na contagem de documentos. Não modifique essa linha; * field: esse será o campo que você deseja fazer a agregação, no nosso caso, por sigla de UF. Você pode modificar esta linha para outra variável categórica; * size: esse é o limite de resultados da agregação. Como temos 27 estados, podemos especificar o tamanho 27. Se colocarmos um tamanho maior, não irá causar nenhum erro. Se o campo de agregação fosse o nome de municípios, devemos usar um número maior (exemplo: 6.000) para obter os resultados de todos os municípios. O limite deste parâmetro é 10.000.

Veja abaixo o resultado desta busca:

es_sim %search% agg_uf
keydoc_count
SP 5312966
RJ 2551434
MG 2342315
RS 1559442
BA 1453919
PR 1302757
PE 1145371
CE 879679
SC 671381
GO 614624
PA 581366
MA 494277
PB 453367
ES 409417
AL 349934
RN 324349
PI 296178
MT 279559
MS 274064
AM 254701
SE 220049
DF 209091
RO 134932
TO 116339
AC 59455
AP 44407
RR 31487

Perceba que estamos realizando contagens em mais de 22 milhões registros. Fazer este tipo de contagem em um computador comum poderia durar horas ou dias. Utilizando o ElasticSearch, isso é feito em menos de 1 segundo.

O resultado dessa consulta pode ser guardado no R na forma de um data.frame, para fazer análises e gráficos.

df <- es_sim %search% agg_uf
str(df)
'data.frame':   27 obs. of  2 variables:
 $ key      : chr  "SP" "RJ" "MG" "RS" ...
 $ doc_count: int  5312966 2551434 2342315 1559442 1453919 1302757 1145371 879679 671381 614624 ...

O comando abaixo retorna um gráfico de barras gerado com base nos dados em df.

# Basic barplot
ggplot(data = df, aes(x = reorder(key, doc_count), y = doc_count)) +
  geom_bar(stat = "identity") +
  labs(x = "key", y = "doc_count")

Agregando com filtros

Na busca acima, temos o total de óbitos por estado para todos os anos e todas as doenças, sem filtros. Podemos tornar essa busca mais precisa incluindo um filtro.

filter_causa_ano <- query('{
    "bool": {
      "must": [
        {
          "query_string": {
            "query": "CAUSABAS:I500 AND ano_obito:2016"
          }
        }
      ]
    }
}')

Com o código acima, estamos criando um objeto chamado filter_causa_ano no R, que será usado na consulta ao ES. O que significa cada linha desse objeto? * query: como visto anteriormente, esse comando declara ao ES que você está requerindo uma busca; * bool: essa cláusula permite a construção de filtros que tenham múltiplos campos. Não modifique essa linha; * query_string: isso declara que será definida uma linha de código que representa uma busca, ou no caso, um filtro. Não modifique essa linha; * query: o valor desta cláusula representa o filtro propriamente dito, que define os campos que você deseja filtrar com base nos seus respectivos valores. Você pode modificar esse filtro conforme necessidade.

Com o filtro definido podemos executar uma busca combinando o filtro filter_causa_ano e a agregação agg_uf:

es_sim %search% (filter_causa_ano + agg_uf)
keydoc_count
SP 3336
MG 1622
RJ 1323
PR 1100
BA 938
RS 766
SC 517
CE 516
GO 504
PE 444
PA 392
MA 377
PB 359
PI 216
RN 204
MT 169
AL 166
ES 126
AM 113
MS 96
RO 84
SE 73
TO 67
DF 61
AC 54
AP 23
RR 15

Agora temos o total de óbitos por estado para o CID I500 no ano de 2016. Note que estamos usando o mesmo objeto de agregação agg_uf.

Podemos agora fazer a mesma busca, agregando por municípios. Precisamos apenas criar o objeto agg_mun e rodar novamente a busca.

agg_mun <- aggs('{
     "a1": {
       "terms": {
         "field": "res_codigo_adotado",
         "size": 6000
       }
     }
 }')
df <- es_sim %search% (filter_causa_ano + agg_mun)
str(df)
'data.frame':   3192 obs. of  2 variables:
 $ key      : chr  "355030" "330455" "292740" "230440" ...
 $ doc_count: int  661 456 91 89 86 85 83 82 80 73 ...

Agregações mais complexas

Essa sintaxe de agregação, apesar de ser facilmente lida, pode ser um pouco complicada para ser escrita devido a quantidade de chaves, aspas e vírgulas necessárias, principalmente em agregações mais complexas. Uma forma interessante de "escrever" agregações maiores é utilizar o Kibana. Crie uma visualização do tipo tabela no Kibana e use todos os filtros e agregações que você quiser. Depois, basta copiar e colar a sintaxe criada pelo Kibana em um objeto no R.

Criamos uma agregação um pouco mais complexa através do Kibana, tendo resultados por UF e separando por sexo. Veja abaixo onde fica essa sintaxe no kibana:

Vamos agora usar a sintaxe da cláusula aggs criada pelo Kibana no R.

É recomendável apenas mudar o nome da agregação. O Kibana nomeia as agregações com números e isso causa alguma dificuldade no R. Trocamos os nomes 2 e 3 para agg1 e agg2, respectivamente.

agg_uf_sexo <- aggs('{
    "agg1": {
      "terms": {
        "field": "res_SIGLA_UF",
        "size": 27,
        "order": {
          "_count": "desc"
        }
      },
      "aggs": {
        "agg2": {
          "terms": {
            "field": "def_sexo",
            "size": 5,
            "order": {
              "_count": "desc"
            }
          }
        }
      }
    }
  }')
df <- es_sim %search% (filter_causa_ano + agg_uf_sexo)

Você pode usar o código abaixo para obter uma tabela no mesmo formato do Kibana.

join_df_agg2 <- function(uf_key,agg2){
   list(cbind(UF = uf_key, Sexo = agg2$key, Obitos = agg2$doc_count))
}


df2 <- do.call("rbind", mapply(join_df_agg2, df$key, df$agg2.buckets, SIMPLIFY = TRUE))
df2
UFSexoObitos
SP Feminino 1866
SP Masculino1470
MG Feminino 812
MG Masculino810
RJ Feminino 684
RJ Masculino639
PR Feminino 596
PR Masculino504
BA Masculino498
BA Feminino 440
RS Feminino 434
RS Masculino332
SC Feminino 302
SC Masculino215
CE Feminino 277
CE Masculino239
GO Masculino269
GO Feminino 235
PE Masculino228
PE Feminino 216
PA Masculino215
PA Feminino 177
MA Masculino201
MA Feminino 176
PB Feminino 190
PB Masculino169
PI Masculino120
PI Feminino 96
RN Feminino 107
RN Masculino97
MT Masculino99
MT Feminino 70
AL Masculino85
AL Feminino 81
ES Feminino 68
ES Masculino58
AM Masculino66
AM Feminino 47
MS Masculino51
MS Feminino 45
RO Masculino48
RO Feminino 36
SE Masculino38
SE Feminino 35
TO Masculino35
TO Feminino 32
DF Feminino 35
DF Masculino26
AC Masculino32
AC Feminino 22
AP Masculino13
AP Feminino 10
RR Feminino 8
RR Masculino7

Fim do tutorial