Baixando e processando dados do DATASUS sobre suicídio com Python

Dalton Costa
Datapsico
Published in
10 min readSep 19, 2020

Poucas pessoas sabem que o DATASUS disponibiliza uma incrível base de dados com milhares de informações sobre a saúde dos brasileiros. Dados públicos e de fácil acesso por qualquer um.

Entre as diversas possibilidades, hoje eu escolhi trabalhar com a temática do suicídio e como esse fenômeno é registrado pelo DATASUS. Além disso, quero demonstrar como baixar e tratar dados do DATASUS utilizando a linguagem Python.

O Andre Pecini fez um artigo discutindo e atualizando o código demonstrado nesse tutorial. Confira o artigo do Andre Pecini nesse link.

Atenção: objetivo desse texto não é discutir o suicídio na sua amplitude e complexidade. O foco é demonstrar como obter e tratar os dados provenientes do DATASUS.

Baixando dados do DATASUS com Python

Uma forma de baixar os dados utilizando Python é utilizando as rotinas propostas pela biblioteca PySUS, desenvolvida por fccoelho. A proposta do PySUS é muito parecida com o conhecido pacote do R chamado microdatasus, no entanto, PySUS é mais limitado do que o microdatasus em termos de funções. Outra forma de baixar os dados é direto pelo site do DATASUS, esses dados serão baixados em formato .dbc, o que pode dificultar sua manipulação se utilizada a linguagem Python.

O DATASUS possuí vários seguimentos de notificação, como o Sistema de Informação de Nascidos Vivos (SINASC) e Sistema de informações de Mortalidade (SIM). O nosso objetivo inicial será baixar os casos de óbitos do Brasil de 2014 a 2018, considerando todos os tipos de óbitos e de todos os estados da federação. Para isso vamos utilizar vamos utilizar os dados do SIM e a função ‘download()’ do PySUS:

#!pip install PySUS
from pysus.online_data.SIM import download
estados =["A","AL","AP","AM","BA","CE","DF","ES","GO","MA","MT", "MS","MG","PA","PB","PR","PE","PI","RJ","RN","RS","RO","RR","SC","SP","SE","TO"]
anos = [2014, 2015, 2016, 2017, 2018]
banco={}for y in anos:
for uf in estados:
banco[uf, y] = download(state = uf, year=y)
print("Banco de " + str(y) + "de " + str(uf) + "baixado!")

Output:

Podemos ler esse código da seguinte forma: primeiro criamos duas listas, a primeira contém os estados do Brasil e a segunda contém os anos que queremos baixar. Em seguida, criamos um dicionário que armazenará cada banco de dados baixado por ano e por estado. Logo chamamos um loop, que irá percorrer cada ano e, em seguida, um segundo loop que irá percorrer cada estado. Por fim, um print com o ano e estado indicando qual banco foi baixado.

Processamento dos Dados

Após termos os dados baixados, todos os bancos estão armazenados na variável “banco”. O processamento que precisamos realizar é a conversão dessa variável (do tipo dicionário) para o tipo DataFrame. Utilizando a função ‘concat()’ da biblioteca Pandas é possível realizar essa conversão:

todos = pd.concat({ k: pd.DataFrame.from_dict(v) for k, v in    banco.items() }, axis=0).reset_index()

Output:

Podemos ler esse código da seguinte forma: Essa função é capaz de ir em cada banco armazenado na variável “banco” e converter cada banco em um DataFrame. Por fim, a função concat() junta todos os bancos em um só DataFrame e resetamos os índices para termos acesso ao estado e ano. Veja a ilustração desse processo abaixo:

Escolhendo Variáveis

Agora temos uma variável chamada “todos” com todos os estados e anos que baixamos organizados em um DataFrame. Agora vamos criar um subset contendo apenas as variáveis que nos interessa.

Variáveis:

  • level_0: UF do caso registrado. Variável criada na etapa anterior, que originalmente era os indes e resetamos (.reset_index())
  • level_1: Ano do caso registrado. Variável criada na etapa anterior, que originalmente era os indes e resetamos (.reset_index())
  • CIRCOBITO: circunstância do óbito. 1 : Acidente, 2 : Suicídio, 3 : Homicídio, 4 : Outro, 0;5;6;7;8;9 : NA.
  • DTOBITO: data do óbito.
  • DTNASC: data de nascimento.
  • SEXO: sexo. 1 : Masculino, 2 : Feminino, 0;9 : NA.
  • RACACOR: raça. 1 : Branca, 2 : Preta, 3 : Amarela, 4 : Parda, 5 : Indígena, 0;6;7;8;9 : NA.
  • ESTCIV: estado civil. 1 : Solteiro, 2 : Casado, 3 : Viúvo, 4 : Separado judicialmente, 5 : União consensual, 0;6;7;8;9 : NA.
  • ESC: escolaridade. 1 : Nenhuma, 2: 1 a 3 anos, 3 : 4 a 7 anos, 4 : 8 a 11 anos, 5 : 12 e mais, 8 : De 9 a 11 anos, 0;6;7;9;A : NA.
  • OCUP: ocupação. Para óbitos a partir de 2006, segue-se a tabela CBO2002.
  • CODMUNRES: município de residência do falecido (codificado).
  • LOCOCOR: Local de ocorrência do óbito. 1 : Hospital, 2 : Outro estabelecimento de saúde, 3 : Domicílio, 4 : Via pública, 5 : Outros, 9 : NA.
  • ASSISTMED: Assistência médica. 1 : Sim, 2 : Não, 9 : NA.
  • CAUSABAS: Causa básica do óbito. Código CID-10.
  • CAUSABAS_O: Causa básica do óbito. Código CID-10.
todos = todos[[
"level_0", "level_1","CIRCOBITO", "DTOBITO","DTNASC", "SEXO", "RACACOR", "ESTCIV", "ESC", "OCUP", "CODMUNRES", "LOCOCOR", "ASSISTMED", "CAUSABAS", "CAUSABAS_O"
]]
todos.rename(columns={"level_0": "estado", "level_1": "ano"}, inplace=True) #renomeando colunas

Output:

Podemos ler esse código da seguinte forma: utilizando os [[ ]] é possível selecionar as variáveis que nos interessa dentro da variável “todos”. Depois de separar as variáveis podemos renomear as variáveis ‘level_0’ e ‘level_1’ para ‘estado’ e ‘ano’.

Filtrando os Casos de Suicídio

Até agora temos todos os casos de óbito sregistrados no DATASUS de 2014 a 2018, mas o que nos interessa mesmo são os casos de suicídio. Para separar apenas os casos de suicídio, vamos filtrar os dados seguindo a mesma metodologia empregada por Lovisi e colaboradores (2009). Vamos filtrar os casos de óbitos tendo como base a Classificação Internacional de Doenças (CID-10), considerando as causas básicas de óbito que variam na CID-10 entre X-60 e X-84 (lesões autoprovocadas intencionalmente).

filter_list=["X{}".format(x) for x in range(600, 850)]cid10 = todos[
todos["CAUSABAS"].isin(filter_list) | todos["CAUSABAS_O"].isin(filter_list)
]

Output:

Podemos ler esse código da seguinte forma: o primeiro passo é criar uma lista com todas as variações possíveis entre X600 a X849, portanto na variável “filter_list” foi criado um loop que varia de 600 a 850. Em seguida, resgatamos a variável “todos” e filtramos os casos que contém como ‘CAUSABAS’ OU ‘CAUSABAS_O’ uma das possibilidades da lista criada.

Você deve estar se perguntando, por que não filtramos os óbitos de suicídio utilizando a variável ‘CIRCOBITO’, que possuí uma classificação para suicídio (código 2)? Nos meus testes, percebi que essa classificação não é muito confiável, mesmo o óbito tendo como causa básica um código da CID-10 entre X-60 a X-84, há vários casos que recebeu uma classificação diferente de 2 (suicídio). Portanto, optei por padronizar o filtro de casos por apenas um padrão, apenas pela CID-10.

Recodificando Valores

Na variável “cid10” temos um DataFrame com apenas casos de suicídio. A partir de agora vamos utilizá-la para analisar os dados e obter insights. Mas antes de começarmos, ainda precisamos recodificar os valores presente em cada variável. Vamos substituir os números por suas respectivas labels.

dictCIRCOBITO = {
"1" : "Acidente",
"2" : "Suicídio",
"3" : "Homicídio",
"4" : "Outro",
"0" : "NA",
"6" : "NA",
"7" : "NA",
"8" : "NA",
"9" : "NA"
}
dicSEXO = {
"1" : "Masculino",
"2" : "Feminino",
"0" : "NA",
"9" : "NA"
}
dicRACACOR = {
"1" : "Branca",
"2" : "Preta",
"3" : "Amarela",
"4" : "Parda",
"5" : "Indígena",
"0" : "NA",
"6" : "NA",
"7" : "NA",
"8" : "NA",
"9" : "NA"
}
dicESTCIV = {
"1" : "Solteiro",
"2" : "Casado",
"3" : "Viúvo",
"4" : "Separado judicialmente",
"5" : "União consensual",
"0" : "NA",
"6" : "NA",
"7" : "NA",
"8" : "NA",
"9" : "NA"
}
dicESC = {
"1" : "Nenhuma",
"2": "1 a 3 anos",
"3" : "4 a 7 anos",
"4" : "8 a 11 anos",
"5" : "12 e mais",
"8" : "De 9 a 11 anos",
"0" : "NA",
"6" : "NA",
"7" : "NA",
"9" : "NA",
"" : "NA"
}
dictLOCOCOR = {
"1" : "Hospital",
"2" : "Outro estabelecimento de saúde",
"3" : "Domicílio",
"4" : "Via pública",
"5" : "Outros",
"9" : "NA"
}
dictASSISTMED = {
"1" : "Sim",
"2" : "Não",
"9" : "NA"
}
cid10 = cid10.replace({"CIRCOBITO" : dictCIRCOBITO, "SEXO" : dicSEXO, "RACACOR" : dicRACACOR, "ESTCIV" : dicESTCIV, "ESC" : dicESC, "LOCOCOR" : dictLOCOCOR, "ASSISTMED" : dictASSISTMED})

Output:

Podemos ler esse código da seguinte forma: primeiro criamos dicionários com os valores e as labels das variáveis ‘CIRCOBITO’, ‘SEXO’, ‘RACACOR’ , ‘ESTCIV’, ‘ESC’, ‘LOCOCOR’ e ‘ASSISTMED’ . Utilizando a função replace(), substituímos os valores das variávei sselecionadas pelos valores (labels) atribuídos nos dicionários criados anteriormente.

Para as variáveis que se referem ao tempo, como ‘DTOBITO’ e ‘DTNASC’ precisamos convertê-las para o formato datatime, para isso iremos utilizar a biblioteca datetime, veja como se faz:

import datetimecid10["DTNASC"] = cid10["DTNASC"][cid10["DTNASC"] != ""].apply(lambda x: datetime.datetime.strptime(x, "%d%m%Y"))cid10["DTOBITO"] = cid10["DTOBITO"][cid10["DTOBITO"] != ""].apply(lambda x: datetime.datetime.strptime(x, "%d%m%Y"))

Output:

Podemos ler esse código da seguinte forma: vamos converter os valores das variáveis ‘DTNASC’ e ‘DTOBITO’ do formato object para o formato datetime, mas precisamos passar apenas valores válidos, portanto, precisamos filtrar casos que tenha data vazia (‘’). Após isso, uma função lambda irá ler e converter cada caso de data na nossa variável e configurá-la para o formato ano-mês- dia.

Aproveitando que estamos trabalhando com datas, podemos calcular a idade das pessoas subtraindo o ano de morte pelo ano de nascimento. Vamos criar uma variável ‘idade’.

cid10["idade"] = cid10["DTOBITO"].dt.year - cid10["DTNASC"].dt.year

Output:

Em relação ao dia do óbito, podemos ainda explorar o mês do ano em que ocorreu. Veja como calcular:

cid10["mes"] = cid10["DTOBITO"].map(lambda x: x.strftime("%m"))

Output:

Entre as variáveis que sobraram foram ‘OCUP’ e ‘CODMUNRES’, que se referem as ocupações e os municípios em que ocorreram os óbitos. No entanto, ambas estão em formato de código e precisamos substituir esses códigos pelas seus respectivas labels (rótulos). As ocupações seguem as codificação proposta pela Classificação Brasileira de Ocupações (CBO) no ano de 2002, já a codificação dos municípios segue os códigos do IBGE. Veja no código abaixo como fazer as substituições.

CBO2002  = pd.read_csv("CBO.csv").set_index("CODIGO").to_dict()cid10["OCUP"] = cid10["OCUP"].replace("", 0).astype(int)
cid10["OCUP"] = cid10["OCUP"].replace(CBO2002["OCUPACAO"])

Podemos ler esse código da seguinte forma: primeiro carregamos o arquivo ‘CBO.csv’ e em seguida realizamos a substituição dos códigos da variável ‘OCUP’ pelas labels. Aqueles casos que não possuem codificação são subsistidos por 0.

Output:

URL = "http://blog.mds.gov.br/redesuas/wp-content/uploads/2018/06/Lista_Munic%C3%ADpios_com_IBGE_Brasil_Versao_CSV.csv"
municipios = pd.read_csv(URL, error_bad_lines=False, sep=";",encoding="latin-1", usecols = ["IBGE","Município"]).set_index("IBGE").to_dict()
cid10["CODMUNRES"]=cid10["CODMUNRES"].astype(int).replace(municipios["Município"])

Podemos ler esse código da seguinte forma: para realizar a substituição dos municípios, dessa vez baixando os dados diretamente por um link. Note que ao ler o arquivo .csv baixado, selecionamos apenas as colunas que nos interessa.

Output:

O seu banco de dados no final estará parecido com esse abaixo. Caso queira baixar esse banco de dados completo acesse nossa página no Kaggle.

Usando Dados Públicos

Agora que temos nossos dados baixados e processados podemos explorá-los. Podemos obter insights por meio de inferências estatísticas ou simplesmente por meio da visualização dos gráficos.

Podemos utilizar dados públicos para criar políticas públicas, explorar novos problemas de pesquisa e entender diversos fenômenos nacionais. Temos um grande tesouro nas mãos e temos que explorá-lo, privilégio que não está presente em outros países.

Vamos explorar dados públicos! Vamos utilizar aquilo que temos direito!

Código Completo

#!pip install PySUS 
from pysus.online_data.SIM import download
import datetime
estados = ["AC", "AL", "AP", "AM", "BA", "CE", "DF", "ES", "GO", "MA", "MT","MS", "MG", "PA", "PB", "PR", "PE", "PI", "RJ", "RN", "RS", "RO", "RR", "SC","SP", "SE", "TO"]
anos = [2014, 2015, 2016, 2017, 2018]
banco = {}
for y in anos:
for uf in estados:
banco[uf, y] = download(state=uf, year=y)
print("Banco de " + str(y) + " de " + str(uf) + " baixado!")
todos = pd.concat({k: pd.DataFrame.from_dict(v) for k, v in banco.items()}, axis=0).reset_index()
todos = todos[[
"level_0", "level_1", "CIRCOBITO", "DTOBITO", "DTNASC", "SEXO", "RACACOR", "ESTCIV", "ESC", "OCUP", "CODMUNRES", "LOCOCOR", "ASSISTMED", "CAUSABAS", "CAUSABAS_O"
]]
todos.rename(columns={"level_0": "estado", "level_1": "ano"}, inplace=True) # renomeando colunas
filter_list = ["X{}".format(x) for x in range(600, 850)]
cid10 = todos[
todos["CAUSABAS"].isin(filter_list) | todos["CAUSABAS_O"].isin(filter_list)
]
dictCIRCOBITO = {
"1": "Acidente",
"2": "Suicídio",
"3": "Homicídio",
"4": "Outro",
"0": "NA",
"6": "NA",
"7": "NA",
"8": "NA",
"9": "NA"
}
dicSEXO = {
"1": "Masculino",
"2": "Feminino",
"0": "NA",
"9": "NA"
}
dicRACACOR = {
"1": "Branca",
"2": "Preta",
"3": "Amarela",
"4": "Parda",
"5": "Indígena",
"0": "NA",
"6": "NA",
"7": "NA",
"8": "NA",
"9": "NA"
}
dicESTCIV = {
"1": "Solteiro",
"2": "Casado",
"3": "Viúvo",
"4": "Separado judicialmente",
"5": "União consensual",
"0": "NA",
"6": "NA",
"7": "NA",
"8": "NA",
"9": "NA"
}
dicESC = {
"1": "Nenhuma",
"2": "1 a 3 anos",
"3": "4 a 7 anos",
"4": "8 a 11 anos",
"5": "12 e mais",
"8": "De 9 a 11 anos",
"0": "NA",
"6": "NA",
"7": "NA",
"9": "NA",
"": "NA"
}
dictLOCOCOR = {
"1": "Hospital",
"2": "Outro estabelecimento de saúde",
"3": "Domicílio",
"4": "Via pública",
"5": "Outros",
"9": "NA"
}
dictASSISTMED = {
"1": "Sim",
"2": "Não",
"9": "NA"
}
cid10 = cid10.replace({"CIRCOBITO": dictCIRCOBITO, "SEXO": dicSEXO, "RACACOR": dicRACACOR,"ESTCIV": dicESTCIV, "ESC": dicESC, "LOCOCOR": dictLOCOCOR, "ASSISTMED": dictASSISTMED})
cid10["DTNASC"] = cid10["DTNASC"][cid10["DTNASC"] != ""].apply(lambda x: datetime.datetime.strptime(x, "%d%m%Y"))
cid10["idade"] = cid10["DTOBITO"].dt.year - cid10["DTNASC"].dt.year
cid10["mes"] = cid10["DTOBITO"].map(lambda x: x.strftime("%m"))
CBO2002 = pd.read_csv("CBO.csv").set_index("CODIGO").to_dict()
cid10["OCUP"] = cid10["OCUP"].replace("", 0).astype(int)
cid10["OCUP"] = cid10["OCUP"].replace(CBO2002["OCUPACAO"])
URL = "http://blog.mds.gov.br/redesuas/wp-content/uploads/2018/06/Lista_Munic%C3%ADpios_com_IBGE_Brasil_Versao_CSV.csv"
municipios = pd.read_csv(URL, error_bad_lines=False, sep=";", encoding="latin-1", usecols=["IBGE", "Município"]).set_index("IBGE").to_dict()
cid10["CODMUNRES"] = cid10["CODMUNRES"].astype(int).replace(municipios["Município"])

Espero que tenha gostado e qualquer dúvida, comentário ou observação é muito bem-vinda! Fique à vontade para se manifestar e vamos aprender juntos! Se preferir, você pode me contatar pelo dalton.bc96@gmail.com

Obrigado pela leitura!

--

--