Sitemap
Rubens C Silveira

Rubens C Silveira

Dengue no Brasil

19 min readJun 22, 2023

Explorando dados primários de dengue com o R

Press enter or click to view image in full size
Ae. aegypti

Vamos explorar a distribuição dos casos de dengue no Brasil e em alguma UF, mas antes disso precisamos entender um pouco do que é essa doença e como é transmitida.

A dengue não é uma doença nova aqui no Brasil, há registros de epidemias de dengue em 1916, em São Paulo, e em 1923, em Niterói, ambas sem diagnóstico laboratorial (estamos falando de mais de 100 anos, a tecnologia disponivel era outra…). Em 1955, uma grande campanha realizada pela Organização Pan-Americana de Saúde levou a erradicar o A. aegypti (vetor do virus causador da dengue) no Brasil e em diversos outros países americanos. No entanto, a campanha não chegou até seu final e o mosquito permaneceu presente em várias ilhas do Caribe, Guianas, Suriname, Venezuela e sul dos Estados Unidos, voltando a espalhar-se. Em 1963, foi comprovada circulação dos sorotipos DENV-2 e DENV-3 em vários países. No fim da década de 60, o Brasil novamente contava com a presença do vetor em suas principais metrópoles (Fiocruz).

A primeira epidemia documentada clínica e laboratorialmente ocorreu em 1981–1982, em Boa Vista (Roraima), causada pelos sorotipos DENV-1 e DENV-4. No ano de 1986, com a introdução do sorotipo DENV-1 no Rio de Janeiro, foram registradas epidemias em diversos estados. A introdução dos sorotipos DENV-2 e DENV-3 ocorreu também pelo Rio de Janeiro, em 1990 e 2000 respectivamente. O DENV-3 apresentou rápida dispersão para 24 estados do país no período de 2001–2003. O DENV-4 foi reintroduzido no país em 2010 no estado de Roraima, dali se espalhou para o resto do país. No Brasil apresenta ciclos endêmicos e epidêmicos, com epidemias explosivas ocorrendo a cada 4 ou 5 anos. Desde a introdução do vírus no país (1981) mais de sete milhões de casos já foram notificados (Fiocruz).

Bem, nesses dois parágrafos temos bastante informações importantes, então antes de continuar vamos deixar aqui algumas observações (e claro, ler o texto original desses parágrafos ajuda muito):

1º — Existem 4 sorotipos de vírus que podem causar a dengue. A recuperação da infecção fornece imunidade vitalícia contra o sorotipo adquirido. Entretanto, a imunidade cruzada para os outros sorotipos após a recuperação é apenas parcial e temporária. Infecções subsequentes aumentam o risco do desenvolvimento de dengue grave (OPAS).

2º — Endemia é definida como a presença habitual de uma doença em uma determinada área geográfica. Pode, também, referir-se a ocorrência usual de uma determinada doença, dentro de uma área (Gordis, L. 2010).

3º — Epidemia é definida como ocorrência em uma comunidade ou região, de uma doença excedendo claramente a expectativa normal (Gordis, L. 2010).

4º — A cada 4 ou 5 anos há uma explosão no nº de casos, isso pode ocorrer devido a substituição do principal vírus que esta circulando (já que após a recuperação você desenvolve imunidade permanente ao vírus que o infectou porém não aos demais)

Agora que fizemos uma breve introdução da doença (vamos nos abster hoje da transmissão o texto ficaria muito longo…) e definimos alguns pontos importantes vamos aos dados, iremos usar dados do SINAN (casos de dengue), SIM (para os óbitos), IBGE (Nº de vidas na região e malha cartográfica) e INMET (para dados de precipitação).

Começando pelo inicio…

O volume de casos, observaremos os dados de 2013 a 2021. Subindo a base de dados e para ela ficar não tão pesada, vamos selecionar apenas algumas variáveis (colunas).

# Pacotes utilizados p/ as análises
library(tidyverse)
library(read.dbc)
library(readxl)
library(microdatasus)
library(forcats)

# Retirar notação científica
options(scipen = 999)

a13 <- read.dbc("bases/casos/DENGBR13.dbc")
a13 <- a13 %>%
select(ID_AGRAVO, SEM_NOT, NU_ANO, SG_UF, CS_RACA, CS_SEXO, NU_IDADE_N, DT_NOTIFIC, ID_MN_RESI)

a14 <- read.dbc("bases/casos/DENGBR14.dbc")
a14 <- a14 %>%
select(ID_AGRAVO, SEM_NOT, NU_ANO, SG_UF, CS_RACA, CS_SEXO, NU_IDADE_N, DT_NOTIFIC, ID_MN_RESI)

a15 <- read.dbc("bases/casos/DENGBR15.dbc")
a15 <- a15 %>%
select(ID_AGRAVO, SEM_NOT, NU_ANO, SG_UF, CS_RACA, CS_SEXO, NU_IDADE_N, DT_NOTIFIC, ID_MN_RESI)

a16 <- read.dbc("bases/casos/DENGBR16.dbc")
a16 <- a16 %>%
select(ID_AGRAVO, SEM_NOT, NU_ANO, SG_UF, CS_RACA, CS_SEXO, NU_IDADE_N, DT_NOTIFIC, ID_MN_RESI)

a17 <- read.dbc("bases/casos/DENGBR17.dbc")
a17 <- a17 %>%
select(ID_AGRAVO, SEM_NOT, NU_ANO, SG_UF, CS_RACA, CS_SEXO, NU_IDADE_N, DT_NOTIFIC, ID_MN_RESI)

a18 <- read.dbc("bases/casos/DENGBR18.dbc")
a18 <- a18 %>%
select(ID_AGRAVO, SEM_NOT, NU_ANO, SG_UF, CS_RACA, CS_SEXO, NU_IDADE_N, DT_NOTIFIC, ID_MN_RESI)

a19 <- read.dbc("bases/casos/DENGBR19.dbc")
a19 <- a19 %>%
select(ID_AGRAVO, SEM_NOT, NU_ANO, SG_UF, CS_RACA, CS_SEXO, NU_IDADE_N, DT_NOTIFIC, ID_MN_RESI)

a20 <- read.dbc("bases/casos/DENGBR20.dbc")
a20 <- a20 %>%
select(ID_AGRAVO, SEM_NOT, NU_ANO, SG_UF, CS_RACA, CS_SEXO, NU_IDADE_N, DT_NOTIFIC, ID_MN_RESI)

a21 <- read.dbc("bases/casos/DENGBR21.dbc")
a21 <- a21 %>%
select(ID_AGRAVO, SEM_NOT, NU_ANO, SG_UF, CS_RACA, CS_SEXO, NU_IDADE_N, DT_NOTIFIC, ID_MN_RESI)

# Unificando tudo em um unica base
df_unido <- rbind(a13, a14, a15, a16, a17, a18, a19, a20, a21)

# Removendo as bases individuais
remove(a13, a14, a15, a16, a17, a18, a19, a20, a21)

# Nº de linhas na base
nrow(df_unido)

Temos 13.462.613 notificações no Brasil nesses 9 anos (uma base relativamente grande), vamos focar na UF com maior incidência (conceito já mencionado no texto “Manipulação de dados com R, exemplo com dados sobre Leishmaniose Visceral no Brasil”) para isso teremos de utilizar uma base com nº de vidas por UF e como população padrão vamos utilizar a projeção do ultimo ano da série.

# Subindo base de população do IBGE de 2021
cod_uf <- read_excel("bases/auxiliares/cod_uf.xlsx")

# Tabela de casos por UF
tab_uf <- df_unido %>%
filter(!is.na(SG_UF)) %>% # excluindo registros sem UF
group_by(SG_UF) %>%
summarise(casos = n())

# Total de casos com UF
sum(tab_uf$casos)

# Unindo a tabela de casos com a de população
tab_uf <- left_join(tab_uf, cod_uf, by = c("SG_UF" = "COD_UF"))

# Calculo da incidência por 1.000 habitantes
tab_uf["incidencia"] <- tab_uf$casos / tab_uf$`pop 2021` * 1000

# Top 3 UFs por nº de casos
tab_uf %>% arrange(desc(casos)) %>% head(3)

# Top 3 UFs por incidência
tab_uf %>% arrange(desc(incidencia)) %>% head(3)

Que interessante ! A UF com maior número de casos (São Paulo) não é a com maior incidência, isso ocorre pois a UF também é a com maior número de vidas. Quando observamos a incidência a UF que se destaca com a maior incidência é o Acre (170,7/1.000hab.). Vamos trabalhar mais detalhadamente com essa UF.

Será que, como descrito na introdução, conseguimos observar uma sazonalidade dos casos no Acre ?

# Selecionando apenas dados do Acre
df_acre <- df_unido %>%
filter(SG_UF == "12")

# Uma pequena validação é: o campo [SEM_NOT] tem de ter 6 digitos (4 do ano e 2 da semana)
df_acre["n_carac"] <- nchar(as.character(df_acre$SEM_NOT))

# Atenção ! O comando table() exclui os valores NA, então se o campo tiver sem
# preenchimento ele não aparecerá
table(df_acre$n_carac)
# Mais seguro (mesmo sendo "mais trabalhoso") usar o comando:
df_acre %>%
group_by(n_carac) %>%
summarise(casos = n())

# Filtrando apenas registros corretos
df_acre <- df_acre %>%
filter(n_carac == 6)

# Gráfico inicial, casos por data de notificação
df_acre %>%
group_by(DT_NOTIFIC) %>%
summarise(vol = n()) %>%
ggplot(aes(x = DT_NOTIFIC, y = vol)) +
geom_line() +
scale_y_continuous(breaks = seq(0,750,250)) +
scale_x_continuous(breaks = seq(as.Date("2013-01-01"),as.Date("2021-12-31"),365.25)) +
labs(x = "Data",
y = "Nº",
title = "Nº de casos por data de notificação"
)
Press enter or click to view image in full size

Algo de errado não está certo, o ano de 2020 está muito estranho e o final da série parece não terminar em 2021 (ultima base que baixamos). Precisaremos investigar mais a base.

Mesmo com o gráfico estranho podemos observar o que foi relatado, 2014 e 2021 com picos atípicos (Outra coisa chama atenção, os picos estão sempre entre o fim de um ano e o inicio do ano seguinte).

# Tabela de casos (notificações) por ano
base_ano <- df_acre %>%
group_by(NU_ANO) %>%
summarise(casos = n())

Com essa tabela simples conseguimos achar algumas coisas estranhas, como o ano de 2012 (mas baixamos de 2013 em diante) precisaremos excluir, o ano de 2020 não existe (vamos subir só a base desse ano para analisar melhor) e casos de 2022, também vamos excluir esses casos.

# Subindo base de 2020
a20 <- read.dbc("C:/Users/rubens.silveira/Desktop/domat/pasta/dengue/DENGBR20.dbc")

# Abrindo base de 2020
View(a20)
Press enter or click to view image in full size

Apenas observando a tabela de 2020 achamos o erro o campo [SEM_NOT] não tem preenchimento e com isso foi excluído no passo anterior. Então, excluímos os dados de 2012 (dados que não deveriam ter vindo), 2020 (que não tem semana de notificação), 2021 (Não faz sentido manter 2021 sem 2020) e 2022 (que não deveria ter vindo também).

# removendo os anos
df_acre <- df_acre %>%
filter(!NU_ANO %in% c("2012","2020","2021", "2022"))

# montando gráfico
df_acre %>%
group_by(DT_NOTIFIC) %>%
summarise(vol = n()) %>%
ggplot(aes(x = DT_NOTIFIC, y = vol)) +
geom_line() +
scale_y_continuous(breaks = seq(0,750,250)) +
scale_x_continuous(breaks = seq(as.Date("2013-01-01"),as.Date("2021-12-31"),365.25)) +
labs(x = "Data",
y = "Nº",
title = "Nº de casos por data de notificação"
)
Press enter or click to view image in full size

Agora sim, um gráfico bem mais organizado mas infelizmente perdemos um ano importante o de 2021. Vamos deixar o gráfico mais “didático”, separando os anos e traçando uma linha no eixo Y, com o nº 200 (alheio).

# Gráfico das notificações por data
df_acre %>%
group_by(DT_NOTIFIC, NU_ANO) %>%
summarise(vol = n()) %>%
ggplot() +
geom_line(aes(x = DT_NOTIFIC, y = vol, color = NU_ANO)) +
geom_hline(yintercept = 200)+ # Linha traçada no eixo Y com valor alheio 200
scale_y_continuous(breaks = seq(0,600,100)) +
scale_x_continuous(breaks = seq(as.Date("2013-01-01"),as.Date("2020-01-01"),365.25)) +
labs(x = "Data",
y = "Nº",
title = "Nº de casos por data de notificação",
color = "Ano"
)
Press enter or click to view image in full size

Como já tínhamos notado o ano de 2014 foi o maior, o único ano no período que observamos que ultrapassou 200 notificações em um dia e os picos em todos os anos estão no inicio e fim do ano, que são épocas mais quentes e chuvosas, que favorece a proliferação do vetor e isso faz com que a interação do vetor e hospedeiro aumente (mosquitos x pessoas).

A explosão de casos impacta de diversas formas na vida das pessoas, uma delas é sobrecarregando o sistema de saúde (Baptista AB, 2022) (mais casos, mais pessoas buscando atendimento), porém isso não significa que a doença será mais letal !

A letalidade é pode ser entendida como uma medida de gravidade da doença, diferente da mortalidade onde é calculado o risco de morrer de uma determinada doença, a letalidade é o risco de morrer tendo em vista que a pessoa já contraiu a doença (Gordis, L. 2010).

Será que o ano de 2014 também possui a maior letalidade ? Será que o o excesso de casos causou um “crise” no sistema local levando a óbitos os pacientes de dengue ? É uma relação difícil de se fazer olhando apenas esses dados e em um texto, vamos ficar na primeira pergunta.

Sobre a fonte de dados vamos utilizar o SIM (Sistema de informação sobre Mortalidade) onde os dados podem ser baixados no mesmo site que o SINAN (No Datasus) porém esse processo é meio lento, ainda mais se quiser mais anos e/ou UFs, e após isso é preciso decodificar os dados, usando os manuais e o questionário, que no caso do SIM é a DO (Declaração de óbito). Para agilizar esse processo iremos usar o pacote microdatasus, muito útil !

O pacote no momento da escrita não está disponível no CRAN, vamos instalar a versão que está no GitHub

# Instalando e carregando o pacote
install.packages("remotes")
remotes::install_github("rfsaldanha/microdatasus")
library(microdatasus)
# Baixando a base da DO de 2013 a 2019 do estado do Acre
do <- fetch_datasus(year_start = 2013, # Ano inicial
year_end = 2019, # Ano final
uf = "AC", # estado/ UF
information_system = "SIM-DO") # Sistema de informação (nesse caso o SIM)

# Decodificando os dados
do <- process_sim(do)

Muito mais rápido e prático, agora vamos pegar os óbitos de dengue, utilizaremos o campo de causa básica [CAUSABAS] preenchido com a CID-10 = A90

# Filtrando os óbitos por dengue e criando campo de ano do óbito
do_dengue <- do %>%
filter(CAUSABAS == "A90") %>%
mutate(ano = substr(DTOBITO,1,4))# selecionando o ano do óbito do campo data do óbito

# Nº de óbitos por ano
do_dengue %>% group_by(ano) %>% summarise(obitos = n())

Estranho :/ Poucos óbitos por dengue…será que o pacote esta trazendo os dados corretos ? Podemos validar pelo tabnet do Datasus (Um tabulador de dados online onde é possível fazer alguns cruzamentos de modo rápido, seguro e fácil).

Press enter or click to view image in full size
tabnet datasus

O pacote está correto, o volume é baixo mesmo ! Muito curioso, e merece maiores investigações mas não hoje…

Get Rubens C Silveira’s stories in your inbox

Join Medium for free to get updates from this writer.

Outra coisa que podemos verificar é se realmente com o aumento das chuvas os casos tendem a aumentar, para isso vamos usar dados de precipitação, que são públicos no site do Instituto Nacional de Meteorologia (INMET) e os casos da capital. Os dados entre 2013 e 2017 foram extraídos da estação de Rio Branco (RIO BRANCO A104), capital do estado e os dados de 2018 e 2019 são da estação de Epitaciolândia (EPITACIOLANDIA A140), essa adaptação foi necessária pois os dados de Rio Branco nos últimos anos estão falhos (inicio do ano com 0 mm de chuva).

# Subindo base de precipitação
estacao13 <- read_excel("preci/chuvas_2013.xlsx")
estacao14 <- read_excel("preci/chuvas_2014.xlsx")
estacao15 <- read_excel("preci/chuvas_2015.xlsx")
estacao16 <- read_excel("preci/chuvas_2016.xlsx")
estacao17 <- read_excel("preci/chuvas_2017.xlsx")
estacao18 <- read_excel("preci/chuvas_2018.xlsx")
estacao19 <- read_excel("preci/chuvas_2019.xlsx")

precipitacao <- rbind(estacao13, estacao14, estacao15, estacao16, estacao17, estacao18, estacao19)
remove(estacao13, estacao14, estacao15, estacao16, estacao17, estacao18, estacao19)

# Ajuste de alguns campos para construção do gráfico
precipitacao["dt"] <- ymd(precipitacao$Data) # data da chuva
precipitacao["ano"] <- substr(precipitacao$Data,1,4) # Ano da chuva

# Gráfico de precipitação
precipitacao %>%
group_by(dt,ano) %>%
summarise(vol = sum(`Chuva [Diaria] (mm)`, na.rm = TRUE)) %>%
ggplot(aes(x = dt, y = vol, color = ano)) +
geom_line() +
scale_x_continuous(breaks = seq(as.Date("2013-01-01"),as.Date("2020-01-01"),365.25)) +
labs(x = "Data",
y = "Precipitação em milímetro (mm)",
title = "Volume de chuva",
color = "Ano"
)
Press enter or click to view image in full size

A distribuição das chuvas se assemelham ao dos casos (maior volume no inicio e final do ano), vamos testar essa hipótese.

# Tabela referência com todos os dias no intervalo
tabela_dt <- as.data.frame(seq.Date(from = as_date("2013-01-01"),
to = as_date("2019-12-31"),
by = "1 day"))

colnames(tabela_dt) <- "data_padrao" # Ajustando o nome do campo

# Base de Rio Branco
df_rio_branco <- df_acre %>%
filter(ID_MN_RESI == 120040) %>%
group_by(DT_NOTIFIC) %>%
summarise(casos = n())

# Unificando as chuvas por dia (a base tras por periodos/horario)
precipitacao <- precipitacao %>%
group_by(dt) %>%
summarise(chuvas = sum(`Chuva [Diaria] (mm)`, na.rm = TRUE))

# Unificando tabela com todos os dias no intervalo e de precipitação
tabela_geral <- left_join(tabela_dt, precipitacao, by = c("data_padrao" = "dt"))

# Unificando tabela com todos os dias no intervalo e de casos
tabela_geral <- left_join(tabela_geral, df_rio_branco, by = c("data_padrao" = "DT_NOTIFIC"))

# Precipitação e casos que estão com NA serão preenchidos com 0
tabela_geral <- tabela_geral %>%
mutate(chuvas = ifelse(is.na(chuvas),0,chuvas),
casos = ifelse(is.na(casos),0,casos))

# Testando correlação entre precipitação e casos de dengue
cor(tabela_geral$chuvas, tabela_geral$casos)

A correlação entre ambos é quase inexistente (0,13331), uma hipótese é que entre a reprodução do vetor e a notificação da doença há um intervalo significante (do ovo até a transmissão do vírus o vetor tem de se desenvolver até a fase adulta, após isso tem de se alimentar em algum infectado, desenvolver a infecção e a transmitir a outro hospedeiro leva mais de 10 dias) para contornar isso podemos agrupar por mês.

Fiocruz

Antes de realizar uma analise por mês, vamos ver se um gráfico com as duas variáveis nos ajuda a elaborar uma outra hipótese

# Gráfico com dois eixos Y, para duas variáveis
ggplot(tabela_geral, aes(x = data_padrao)) +
geom_line(aes(y = chuvas, colour = "Chuvas"))+
geom_line(aes(y = casos, colour = "Casos")) +
scale_y_continuous(sec.axis = sec_axis(~ . *1 ), limits = c(0, 120)) +
scale_x_continuous(breaks = seq(as.Date("2013-01-01"),as.Date("2021-12-31"),365.25)) +
labs(x = "Data",
y = "Nº",
title = "Nº de casos e precipitação por data",
color = "Evento"
)
Press enter or click to view image in full size

Quando observamos o gráfico, os casos estão levemente deslocados para direita quando observamos os picos de chuva (em quase todos os anos, também interessante notar que aquele pico de 2014 que vimos no estado, desaparece mas em 2013, 2015 e 2019 há picos que se destacam dos demais sugerindo que em algum outro local do estado ocorreu um pico em 2014). Talvez agrupar por mês de um resultado melhor.

# Criando campo de mês e ano
tabela_geral["mes_ano"] <- substr(tabela_geral$data_padrao,1,7)

# Chuvas e casos por mês
tab_mes_ano <- tabela_geral %>%
group_by(mes_ano) %>%
summarise(precipitacao = sum(chuvas),
casos = sum(casos))

# Testando correlação
cor(tab_mes_ano$precipitacao, tab_mes_ano$casos)

# Gráfico de dispersão
ggplot(tab_mes_ano) +
geom_point(aes(y = casos, x = precipitacao)) +
labs(x = "Precipitação em milímetro (mm)",
y = "Casos",
title = "Casos por precipitação"
)
Press enter or click to view image in full size

A situação melhorou um “pocado”, uma correlação de 0,45192 mas ainda é fraco, e observando o gráfico observamos um número relativamente alto de meses sem chuvas e que tem casos, provavelmente há outras variáveis que impactam, como exemplo, temperatura, número de casos anterior, qual vírus está circulando, mínimo de casos para manter o vírus circulando na população e etc…

Bem agora que demos uma olhada na distribuição dos casos no tempo, tentamos achar algo sobre mortes mas eram poucos casos (3 óbitos) e por fim relacionar com as chuvas mas observamos que há mais coisas envolvidas na transmissão, vamos descrever um pouco melhor essa população, será que são mais homens ? idosos ? brancos ?…

Começamos pelo mais simples, o campo sexo e idade. A base populacional veio do DataSus que utiliza a projeção do IBGE para o ano de 2015 (metade da série que temos de casos, mas poderia ser outro ano).

Queremos o campo idade em anos, então teremos de transformar os que não são (horas, dias e meses) em anos. Vamos criar uma nova variável, chamada de [idade_anos], e aproveitaremos para classificar essas população em alguns grupos de faixa etária [faixa_etária].

# separando a unidade de medida
df_acre["medida_idade"] <- substr(df_acre$NU_IDADE_N,1,1)

# classificando a unidade de medida, esse "de/para" esta no manual
df_acre["medida_idade"] <- ifelse(df_acre$medida_idade == "1","Horas", # se igual a 1 são horas
ifelse(df_acre$medida_idade == "2","Dias", # se igual a 2 são dias
ifelse(df_acre$medida_idade == "3","Meses", # se igual a 3 são meses
ifelse(df_acre$medida_idade == "4","Anos","Sem class.")))) # se igual a 4 são anos e se não for nenhum deles é sem classificação

# Separando o valor da idade
df_acre["valor_idade"] <- as.numeric(substr(df_acre$NU_IDADE_N,2,4)) # transformando em número (estava como caracter) os ultimos 3 digitos

# campo de idade em anos
df_acre["idade_anos"] <- ifelse(df_acre$medida_idade == "Horas", df_acre$valor_idade/8760, # 1 ano tem 8.760 horas
ifelse(df_acre$medida_idade == "Dias", df_acre$valor_idade/365, # 1 ano tem 365 dias
ifelse(df_acre$medida_idade == "Meses", df_acre$valor_idade/12, # 1 ano tem 12 meses
ifelse(df_acre$medida_idade == "Anos", df_acre$valor_idade, # se ja esta em anos, não precisamos transformar
ifelse(df_acre$medida_idade == "Sem class", NA,"Erro"))))) # e se não temos uma classe, deixamos vazio (NA), e o erro é para caso nenhuma condição seja atendida

df_acre["idade_anos"] <- as.numeric(df_acre$idade_anos)

# Criando o campo de faixa etária, de 10 em 10 anos, até 100 anos, tudo maior ou igual a 100 anos foi agrupado
df_acre["faixa_etaria"] <- ifelse(df_acre$idade_anos >= 0 & df_acre$idade_anos < 5,"01. 0 a 4 anos",
ifelse(df_acre$idade_anos < 10,"02. 5 a 9 anos",
ifelse(df_acre$idade_anos < 15,"03. 10 a 14 anos",
ifelse(df_acre$idade_anos < 20,"04. 15 a 19 anos",
ifelse(df_acre$idade_anos < 30,"05. 20 a 29 anos",
ifelse(df_acre$idade_anos < 40,"06. 30 a 39 anos",
ifelse(df_acre$idade_anos < 50,"07. 40 a 49 anos",
ifelse(df_acre$idade_anos < 60,"08. 50 a 59 anos",
ifelse(df_acre$idade_anos < 70,"09. 60 a 69 anos",
ifelse(df_acre$idade_anos < 80,"10. 70 a 79 anos",
"11. 80 anos e mais"))))))))))

# Tabela por idade e sexo
tb_idade_sexo <- df_acre %>%
group_by(faixa_etaria, CS_SEXO) %>%
summarise(vol = n()) %>%
ungroup() %>%
spread(CS_SEXO, vol)

view(tb_idade_sexo)

Observamos que temos sexo sem preenchimento (NA) e como não identificado (I).

Agora sim a tabela esta bem melhor, além disso acrescentamos uma coluna de total. Observamos que a maioria dos casos são do sexo feminino, e principalmente em idade economicamente ativa (15 a 59 anos).

# Tabela por idade e sexo apenas com dados validos
tb_idade_sexo <- df_acre %>%
filter(!is.na(CS_SEXO) & CS_SEXO != "I") %>% # Excluindo NA e sexo indefinido
group_by(faixa_etaria, CS_SEXO) %>%
summarise(vol = n()) %>%
ungroup() %>%
spread(CS_SEXO, vol) %>%
mutate(total = F + M) # Criando campo de total

view(tb_idade_sexo)

sum(tb_idade_sexo$F)
sum(tb_idade_sexo$M)

Mas com isso vem a pergunta que nos acompanha…”O número de casos são maiores em um certo grupo apenas por esse ser o maior grupo ?”, para testar isso vamos usar a base da projeção de vidas do IBGE para o ano de 2021.

# Subindo base de vidas
pop_acre_2021_sexo_idade <- read_excel("C:/Users/rubens.silveira/Downloads/pop_acre_2021_sexo_idade.xlsx",
range = "A5:D16", col_types = c("text","numeric", "numeric", "numeric"))

# Calculando a incidencia de casos por sexo e faixa etária

pop_acre_2021_sexo_idade["inc_masc"] <- round(tb_idade_sexo$M / pop_acre_2021_sexo_idade$Masculino * 1000,1)
pop_acre_2021_sexo_idade["inc_fem"] <- round(tb_idade_sexo$F / pop_acre_2021_sexo_idade$Feminino * 1000,1)
pop_acre_2021_sexo_idade["inc_total"] <- round(tb_idade_sexo$total / pop_acre_2021_sexo_idade$Total * 1000,1)

incidencia <- pop_acre_2021_sexo_idade %>%
select(`Faixa Etária 2`,inc_masc, inc_fem, inc_total)

Conseguimos observar que nas faixas etárias de jovens e adultos jovens há maior incidência, mas ainda tem muitas faixas etárias. Para solucionar isso vamos agrupar em 4 grupos (crianças [0 a 9 anos], adolescentes [10 a 19 anos], adultos [20 a 59 anos] e idosos [60 e mais]).

# agrupando bases de casos e vidas
# Casos
tb_idade_sexo["grupo"] <- ifelse(tb_idade_sexo$faixa_etaria == "01. 0 a 4 anos","criança",
ifelse(tb_idade_sexo$faixa_etaria == "02. 5 a 9 anos","criança",
ifelse(tb_idade_sexo$faixa_etaria == "03. 10 a 14 anos","adolescente",
ifelse(tb_idade_sexo$faixa_etaria == "04. 15 a 19 anos","adolescente",
ifelse(tb_idade_sexo$faixa_etaria == "09. 60 a 69 anos","idosos",
ifelse(tb_idade_sexo$faixa_etaria == "10. 70 a 79 anos","idosos",
ifelse(tb_idade_sexo$faixa_etaria == "11. 80 anos e mais","idosos",
"adultos")))))))

tb_casos <- tb_idade_sexo %>%
group_by(grupo) %>%
summarise(fem = sum(F),
mas = sum(M),
total = sum(total))

# Vidas
pop_acre_2021_sexo_idade["grupo"] <- ifelse(pop_acre_2021_sexo_idade$`Faixa Etária 2` == "0 a 4 anos","criança",
ifelse(pop_acre_2021_sexo_idade$`Faixa Etária 2` == "5 a 9 anos","criança",
ifelse(pop_acre_2021_sexo_idade$`Faixa Etária 2` == "10 a 14 anos","adolescente",
ifelse(pop_acre_2021_sexo_idade$`Faixa Etária 2` == "15 a 19 anos","adolescente",
ifelse(pop_acre_2021_sexo_idade$`Faixa Etária 2` == "60 a 69 anos","idosos",
ifelse(pop_acre_2021_sexo_idade$`Faixa Etária 2` == "70 a 79 anos","idosos",
ifelse(pop_acre_2021_sexo_idade$`Faixa Etária 2` == "80 anos e mais","idosos",
"adultos")))))))

tb_vidas <- pop_acre_2021_sexo_idade %>%
group_by(grupo) %>%
summarise(fem = sum(Feminino),
mas = sum(Masculino),
total = sum(Total))

# Calculando a incidencia

tb_casos["inc_fem"] <- tb_casos$fem / tb_vidas$fem * 1000
tb_casos["inc_mas"] <- tb_casos$mas / tb_vidas$mas * 1000
tb_casos["inc_total"] <- tb_casos$total / tb_vidas$total * 1000

tb_inc <- tb_casos %>%
select(grupo, inc_fem, inc_mas, inc_total)

# incidencia por sexo

sum(tb_casos$fem) / sum(tb_vidas$fem) * 1000
sum(tb_casos$mas) / sum(tb_vidas$mas) * 1000
sum(tb_casos$total) / sum(tb_vidas$total) * 1000

Em ambos os sexos os adultos possuem maior incidência. Apenas no grupo de crianças a incidência foi maior no homens, com uma diferença bem pequena.

De modo geral a incidência foi de 118,31/1.000hab. no sexo masculino foi de 111,52/1.000hab e no feminino foi de 125,20/1.000hab.
Para encerrarmos essa parte vamos testar a hipótese que os casos não possuem relação entre os grupos etários e sexo, para isso utilizaremos o teste de qui-quadrado. Em resumo o teste compara a distribuição de alguma coisa (no nosso caso, casos de dengue) entre variáveis categóricas (sexo e grupo etário).

# tabela de casos, teste de qui-quadrado

casos_sexo <- tb_casos %>%
select(fem, mas)

chisq.test(casos_sexo) # Teste do qui-quadrado

Bem, o teste deu que há diferença entre os grupos e com a a analise anterior que fizemos podemos afirmar que mulheres possuem maior incidência de casos, com destaque para o grupo de adultos.

Agora podemos ir para a parte final…os casos estão distribuídos por igual entre as pessoas de raça/cor diferentes ?

Para iniciarmos iremos decodificar o campo CS_RACA pois ele vem preenchido com números (1 a 5 e o 9 para ignorado), os campos sem preenchimento vamos chamar de ignorado também.

# decodificando a base

df_acre["raca_cor"] <- ifelse(is.na(df_acre$CS_RACA),"Sem info.", # verificando se o campo está em branco
ifelse(df_acre$CS_RACA == 1,"Branca",
ifelse(df_acre$CS_RACA == 2,"Preta",
ifelse(df_acre$CS_RACA == 3,"Amarela",
ifelse(df_acre$CS_RACA == 4,"Parda",
ifelse(df_acre$CS_RACA == 5,"Indigena",
ifelse(df_acre$CS_RACA == 9,"Ignorada","Erro")))))))

Agora sim podemos começar…

# Criando gráfico da proporção de casos por raça/cor
df_acre %>%
group_by(raca_cor) %>%
summarise(vol = n()) %>%
mutate(prop = round(vol /sum(vol)*100,2),
raca_cor = fct_reorder(raca_cor, prop)) %>%
ggplot(aes(x = raca_cor, y = prop)) +
geom_col(fill = "purple") +
geom_label(aes(label = prop)) +
labs(title = "Proporção de casos por raça/cor",
x = "Raça/cor",
y = "%")+
coord_flip()
Press enter or click to view image in full size

Diferente, temos aproximadamente 12% dos casos sem o preenchimento de raça/cor, ocupando o segundo lugar. Em primeiro são as pessoas pardas com quase 78%, um volume bem elevado mas observado em outros locais também. Vamos calcular a incidência por raça/cor também, para isso vamos usar a projeção do da população para o ano de 2021 (infelizmente ainda não temos os dados do CENSO).

# Criando base de dados com população por raça/cor 
pop <- data.frame(raca_cor = c("Parda", "Branca", "Preta", "Amarela", "Indigena"),
populacao = c(606398, 211720, 51363, 17807, 19414))

# Criando base com os casos agrupados por raça/cor
tab_raca_cor <- df_acre %>%
group_by(raca_cor) %>%
summarise(vol = n())

# cruzando as bases
tab_raca_cor <- left_join(tab_raca_cor, pop, by = "raca_cor")

# Calculo de incidência
tab_raca_cor["incidencia por 1000hab"] <- round(tab_raca_cor$vol / tab_raca_cor$populacao * 1000,3)

# Gráfico de incidência por raça/cor
tab_raca_cor %>%
filter(!is.na(`incidencia por 1000hab`)) %>%
mutate(raca_cor = fct_reorder(raca_cor, `incidencia por 1000hab`)) %>%
ggplot(aes(x = raca_cor, y = `incidencia por 1000hab`)) +
geom_col(fill = "darkorange") +
geom_label(aes(label = `incidencia por 1000hab`)) +
labs(title = "Incidência por 1.000hab. por raça/cor",
x = "Raça/cor",
y = "/1.000hab.")+
coord_flip()

# Calculo do RR
tab_raca_cor[5,4] / tab_raca_cor[2,4]
Press enter or click to view image in full size

A população parda é a maior incidência (e maior nº de vidas), a população indígena é que possui menor incidência. Olha que curioso, a população parda possuía 3,7 x o risco da população branca de ter dengue no Acre entre 2013 e 2019, esse indicador é definido como risco relativo (RR) que é é a probabilidade de ocorrência do evento entre expostos em relação aos não expostos ao fator de risco, no nosso caso é a probabilidade de ter dengue sendo pardo em comparação a probabilidade de ter dengue sendo branco.

No caso da dengue as condições ambientes em que a população parda está inserida é o que está causando esse “aumento” do risco em relação a população branca e não algum fator biológico/genético que predispõe a população ter dengue.

De forma geral, a ideia foi explorar um pouco sobre a Dengue uma doença que de tempos em tempos causa uma epidemia aqui no Brasil, expondo o perfil das pessoas acometidas na principais UF afetada. Tentei mostrar outras fontes de dados (não só dados de saúde) que podemos usar para tentar compreender um evento. Junto a isso explorar um pouco dos dados, que na vida real, não estão disponíveis com uma “ótima qualidade” e exercitar algumas funções no R como criar variáveis, construir algumas tabelas e alguns gráficos. Foi uma maneira de abordar um pouco de epidemiologia e programação (linguagem R).

O script, as bases e alguns documentos de apoio estão no GitHub

Referências:

Gordis L. Epidemiologia. Editora Revinter. 2010. 4ª Edição.

--

--