Vídeos tutoriais para a interface Análise Visual
|
|
Tutorial em R para acesso à interface tecnológica Mineração de Dados e Análise Preditiva
|
|
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.
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
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 <- "usuario.padrao"
es_pwd <- "!PCD%40SizOoCN3!"
#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")
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"
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.
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
key | doc_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")
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)
key | doc_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 ...
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
UF | Sexo | Obitos |
---|---|---|
SP | Feminino | 1866 |
SP | Masculino | 1470 |
MG | Feminino | 812 |
MG | Masculino | 810 |
RJ | Feminino | 684 |
RJ | Masculino | 639 |
PR | Feminino | 596 |
PR | Masculino | 504 |
BA | Masculino | 498 |
BA | Feminino | 440 |
RS | Feminino | 434 |
RS | Masculino | 332 |
SC | Feminino | 302 |
SC | Masculino | 215 |
CE | Feminino | 277 |
CE | Masculino | 239 |
GO | Masculino | 269 |
GO | Feminino | 235 |
PE | Masculino | 228 |
PE | Feminino | 216 |
PA | Masculino | 215 |
PA | Feminino | 177 |
MA | Masculino | 201 |
MA | Feminino | 176 |
PB | Feminino | 190 |
PB | Masculino | 169 |
PI | Masculino | 120 |
PI | Feminino | 96 |
RN | Feminino | 107 |
RN | Masculino | 97 |
MT | Masculino | 99 |
MT | Feminino | 70 |
AL | Masculino | 85 |
AL | Feminino | 81 |
ES | Feminino | 68 |
ES | Masculino | 58 |
AM | Masculino | 66 |
AM | Feminino | 47 |
MS | Masculino | 51 |
MS | Feminino | 45 |
RO | Masculino | 48 |
RO | Feminino | 36 |
SE | Masculino | 38 |
SE | Feminino | 35 |
TO | Masculino | 35 |
TO | Feminino | 32 |
DF | Feminino | 35 |
DF | Masculino | 26 |
AC | Masculino | 32 |
AC | Feminino | 22 |
AP | Masculino | 13 |
AP | Feminino | 10 |
RR | Feminino | 8 |
RR | Masculino | 7 |
Fim do tutorial