Download e pré-processamento de dados de violência do Sinan/DATASUS com Python

André Pecini
Datapsico
Published in
6 min readApr 5, 2023
Créditos da imagem: Paulo H. Carvalho / Agência Brasília

O título parecido não é mera coincidência, este texto foi diretamente inspirado pelo Baixando e processando dados do DATASUS sobre suicídio com Python, do Dalton Costa, que também me ajudou a organizar as ideias para escrevê-lo aqui e a quem eu agradeço (agora, publicamente).

A ideia é deixar disponível aqui uma forma de acessar e decodificar os dados do DATASUS sobre violência interpessoal. É um texto de um iniciante na linguagem Python. Por isso, o código provavelment enão está otimizado ou “pythonizado”. Mas, dada sua simplicidade, ele funciona. Contudo, quaisquer sugestões ou correções são bem-vindas.

Antes do texto, acho importante dizer que este trabalho é fruto parcial de pesquisa realizada com financiamento da CAPES, emum processo de Cooperação Acadêmica (PROCAD) na área de Segurança Pública e Ciências Forenses, sob o qual fiz um estágio pós-doutoral no Programa de Pós-Graduação em Gestão da Informação da UFPR. Portanto, entendo que é mais do que justo deixar este conteúdo público e acessível, além de contribuir, mesmo que modestamente, para auxiliar outros(as) pesquisadores(as) a acessar e trabalhar com os dados também públicos do DATASUS.

Assim como o Dalton fez, adianto que não sou especialista em segurança pública e aqui não serão discutidas suas causas, nem hipóteses para combatê-la. O texto diz respeito apenas ao processo de download e “tradução” dos dados em Python.

Download das bases de dados Sinan/DATASUS

Atualização: seguindo sugestão do Dalton, deixo aqui o link para o código completo no Google Colab para que possam testar seu funcionamento e copiar mais facilmente.

Existem diversas formas de baixar as bases. A mais simples é com o uso do PySUS, conforme o Dalton explica. no texto. No entanto, o DATASUS parece ter mudado a forma de organizar os arquivos e este método deixou de funcionar. O comando disponível na documentação do PySUS < df = SINAN.download(2019,’CHAGAS’) > também retorna erro. O código abaixo parece fazer o download, mas retorna um objeto do tipo string.

df = SINAN.download('Violência Domestica', 2019)

Por isso, o método que usei foi o de baixar o arquivo .DBC diretamente do site do DATASUS , subir no Google Colab e fazer a conversão com o PySUS, de acordo com a documentação, que reproduzo abaixo:

from pysus.utilities.readdbc import read_dbc

df = read_dbc(filename, encoding='iso-8859-1')
df.info()

O passo seguinte é limpar a base de dados de registros duplicados e aqueles que não interessam à pesquisa sobre violência interpessoal: lesão autoprovocada e aqueles em que o autor da lesão é identificado como a própria vítima (o que pode parecer redundante, mas como existem esses dois atributos, vale a pena usar os dados de ambos).

df = df[df['NDUPLIC'] != '1']

# Remover registros de lesão autoprovocada e cujo autor é provavelmente a própria vítima
df = df[df['REL_PROPRI'] != '1']
df = df[df['LES_AUTOP'] != '1']

# Remover as colunas de duplicidade, lesão autoprovocada e cujo autor é provavelmente a própria vítima
df = df.drop(columns=['REL_PROPRI', 'LES_AUTOP', 'NDUPLIC'])

df.reset_index(level=0, inplace=True, drop=True)
df.info()

O passo seguinte é selecionar as colunas (os atributos) adequados às análises que o(a) pesquisador(a) deseja realizar. A descrição das colunas e dos códigos de preenchimento se encontra no dicionário de variáveis. Encontrei mais de uma versão, esta parece ser a mais atualizada. A base de dados do Sinan tinha cerca de 170 colunas. No último download, o arquivo tinha 158. Segue um exemplo do código para realizar a seleção de colunas no DataFrame do pandas:

colunas = ['DT_NASC', 'CS_SEXO', 'CS_RACA', 'CS_ESCOL_N', 'SIT_CONJUG', 
'ORIENT_SEX', 'IDENT_GEN','DT_OCOR','DT_NOTIFIC', 'SG_UF_OCOR',
'LOCAL_OCOR', 'OUT_VEZES', 'VIOL_FISIC', 'VIOL_PSICO', 'VIOL_TORT',
'VIOL_SEXU', 'VIOL_FINAN', 'VIOL_NEGLI', 'VIOL_ESPEC', 'VIOL_TRAF',
'VIOL_INFAN', 'VIOL_OUTR', 'VIOL_MOTIV', 'LES_AUTOP', 'NDUPLIC',
'DT_OBITO', 'REL_PAI', 'REL_MAE', 'REL_PAD', 'REL_CONJ', 'REL_EXCON',
'REL_NAMO', 'REL_EXNAM', 'REL_FILHO', 'REL_DESCO', 'REL_IRMAO',
'REL_CONHEC', 'REL_CUIDA', 'REL_PATRAO', 'REL_INST', 'REL_POL',
'REL_MAD', 'REL_TRAB', 'REL_PROPRI', 'REL_OUTROS', 'NU_IDADE_N',
'ASSIST_SOC', 'REDE_EDUCA', 'CONS_TUTEL','CONS_IDO','DELEG_IDOS',
'DIR_HUMAN', 'MPU', 'DELEG_CRIA', 'DELEG_MULH', 'DELEG', 'INFAN_JUV',
'DEFEN_PUBL']

df = df[df.columns.intersection(colunas)]

Atualização: acabei de notar que incluí as colunas, mas não fiz os dicionários para decodificar as colunas do atributo “ENC_”, referentes ao “encaminhamento
da pessoa atendida”, segundo o dicionário de dados (delegacia da mulher, conselho tutelar etc.). Trabalho a ser feito no futuro.

A idade das vítimas é registrada com um código um tanto complexo na coluna NU_IDADE_N. De acordo com o dicionário de variáveis, “A composição da variável obedece o seguinte critério: 1o dígito: 1. Hora 2. Dia 3. Mês 4. Ano Ex: 3009 — nove meses, 4018 — dezoito anos”. ANtes de converter para anos, é necessário remover os valores ausentes (“NaN”):

df=df.dropna(subset=['NU_IDADE_N']).reset_index(drop=True)

O pacote PySUS tem um decodificador de idade, que funciona com o seguinte código:

from pysus.preprocessing.decoders import decodifica_idade_SINAN

df['NU_IDADE_N'] = pd.to_numeric(df['NU_IDADE_N'], errors='coerce')

df['Idade'] = decodifica_idade_SINAN(df.NU_IDADE_N, 'Y')

Pronto, assim o DataFrame (df) já é uma base com a qual se pode fazer análises estatísticas ou qualquer outro tipo de investigação. Contudo, uma etapa que se mostra um tanto trabalhosa (apesar de ser muito simples) é a conversão dos valores em suas descrições no dicionário de variáveis do DATASUS. Por exemplo, o código para situação conjugal (coluna SIT_CONJUG) é:

1- Solteiro
2- Casado/ União consensual
3- Viúvo
4- Separado
8- Não se aplica
9- Ignorado

Além disso, é importante para qualquer análise queconsidere este atributo saber o que o código 8 significa: “Categoria 8 se idade do paciente for < 10 anos”.

Este exemplo também mostra outro desafio do trabalho com esses dados: não encontrei este atributo no dicionário de dados mencionado acima. Ele está presente em outra versão, disponível aqui.

Por ter feito o trabalho de decodificação dos dados de diversas colunas (seguindo novamente o código do Dalton), deixo aqui os dicionários Python para agilizar o trabalho de quem precisar fazer isso.

#Estado / Unidade Federativa

df_dic['SG_UF_OCOR'] = df_dic['SG_UF_OCOR'].map({'11':'Rondônia', '12':'Acre',
'13':'Amazonas', '14':'Roraima',
'15':'Pará', '16':'Amapá', '17':'Tocantins',
'21':'Maranhão', '22':'Piauí', '23':'Ceará',
'24':'Rio Grande do Norte', '25':'Paraíba',
'26':'Pernambuco', '27':'Alagoas',
'28':'Sergipe', '29':'Bahia',
'31':'Minas Gerais', '32':'Espírito Santo',
'33':'Rio de Janeiro', '35':'São Paulo',
'41':'Paraná', '42':'Santa Catarina',
'43':'Rio Grande do Sul',
'50':'Mato Grosso do Sul',
'51':'Mato Grosso', '52':'Goiás',
'53':'Distrito Federal'})
print(df_dic.SG_UF_OCOR.value_counts())
#Orientação Sexual

df_dic['ORIENT_SEX'] = df_dic['ORIENT_SEX'].map({'1' : 'Heterossexual',
'2' : 'Homossexual',
'3' : 'Bissexual',
'8' : 'Não se aplica',
'9' : 'Ignorada'})
print(df_dic.ORIENT_SEX.value_counts())
#Identidade de gênero

df_dic['IDENT_GEN'] = df_dic['IDENT_GEN'].map({'1' : 'Travesti',
'2' : 'Transexual Mulher',
'3' : 'Transexual Homem',
'8' : 'Não se aplica',
'9' : 'Ignorada'})
print(df_dic.IDENT_GEN.value_counts())
#Raça/cor

df_dic['CS_RACA'] = df_dic['CS_RACA'].map({'1' : 'Branca',
'2' : 'Preta',
'3' : 'Amarela',
'4' : 'Parda',
'5' : 'Indígena',
'9' : 'Ignorada'})
print(df_dic.CS_RACA.value_counts())
#Escolaridade

df_dic['CS_ESCOL_N'] = df_dic['CS_ESCOL_N'].map({'00' : 'Analfabeto(a)',
'01':'1a-4a incompleta',
'02':'4a completa',
'03':'5a-8a incompleta',
'04':'Fundamental completo',
'05': 'Ensino Médio incompleto',
'06':'Ensino Médio completo',
'07':'Ed. Superior incompleta',
'08':'Ed. Superior completa',
'09':'Ignorado',
'10':'Não se aplica'})
print(df_dic.CS_ESCOL_N.value_counts())
#Situação conjugal

df_dic['SIT_CONJUG'] = df_dic['SIT_CONJUG'].map({'1' : 'Solteiro',
'2' : 'Casado/União Consensual',
'3' : 'Viúvo',
'4' : 'Separado',
'8' : 'Não se aplica',
'9' : 'Ignorado'})
print(df_dic.SIT_CONJUG.value_counts())
#Local de ocorrência

df_dic['LOCAL_OCOR'] = df_dic['LOCAL_OCOR'].map({'01': 'Residência',
'02': 'Habitação coletiva',
'03': 'Escola',
'04': 'Local de prática esportiva',
'05': 'Bar ou similar',
'06': 'Via pública',
'07': 'Comércio/Serviços',
'08': 'Industrias/ construção',
'09': 'Outro',
'99': 'Ignorado'})
print(df_dic.LOCAL_OCOR.value_counts())
#Motivação da violência

df_dic['VIOL_MOTIV'] = df_dic['VIOL_MOTIV'].map({'01':'Sexismo',
'02':'Homo/Lesbo/Transfobia',
'03':'Racismo',
'04':'Intolerância religiosa',
'05':'Xenofobia',
'06':'Conflito geracional',
'07': 'Situação de rua',
'08':'Deficiência',
'09':'Outros',
'88':'Não se aplica',
'99':'Ignorado'})
print(df_dic.VIOL_MOTIV.value_counts())
# Substituição de valores nos atributos com múltiplas colunas

#Relações
d_rel = {'REL_PAI':'Pai',
'REL_MAE' : 'Mãe',
'REL_PAD' : 'Padrasto ',
'REL_CONJ' : 'Cônjuge ',
'REL_EXCON':'Ex-cônjuge ',
'REL_NAMO':'Namorado(a) ',
'REL_EXNAM':'Ex-namorado(a) ',
'REL_FILHO':'Filho(a) ',
'REL_DESCO': 'Desconhecido(a) ',
'REL_IRMAO':'Irmã(o) ',
'REL_CONHEC':'Amigo(a)/Conhec. ',
'REL_CUIDA':'Cuidador(a) ',
'REL_PATRAO':'Chefe ',
'REL_INST':'Institucional ',
'REL_POL':'Policial ',
'REL_OUTROS':'Outros ',
'REL_TRAB':'Trabalho ',
'REL_MAD':'Madrasta '}

#Forma de violência
d_viol = {'VIOL_FISIC' : 'Física ',
'VIOL_PSICO': 'Psicológica ',
'VIOL_TORT': 'Tortura ',
'VIOL_SEXU': 'Sexual ',
'VIOL_TRAF': 'Tráfico humano ',
'VIOL_FINAN': 'Financeira ',
'VIOL_NEGLI': 'Negligência/Abandono ',
'VIOL_INFAN': 'Trabalho infantil ',
'VIOL_OUTR': 'Violência (Outra) '}

#Encaminhamento por
d_enc = {'ASSIST_SOC':'Assist. Social ',
'REDE_EDUCA':'Rede Educação ',
'CONS_TUTEL':'Conselho Tutelar ',
'CONS_IDO':'Conselho do Idoso ',
'DELEG_IDOS':'Delegacia Idoso ',
'DIR_HUMAN':'Centro Ref. DH ',
'MPU':'Ministério Público ',
'DELEG_CRIA':'Delegacia Criança/Adolescente',
'DELEG_MULH':'Delegacia Mulher ',
'DELEG':'Delegacia (Outra)',
'INFAN_JUV':'Justiça Infância/Juventude ',
'DEFEN_PUBL':'Defensoria Pública '}

dicionarios = {**d_rel, **d_viol, **d_enc}

for key in dicionarios:
df_dic[key] = df_dic[key].apply(lambda x: str(dicionarios[key]) if x == '1' else '')
print(df_dic[key].value_counts())

Para salvar a tabela resultante em um arquivo .CSV, seja como backup ou para continuar o trabalho em ambientes online que não salvam a sessão como o Google Colab, use este código:

df.to_csv('NomeDoArquivo.csv', sep=';')

--

--

André Pecini
Datapsico

Doutorado em Tecnologias da Comunicação (ECO-UFRJ). Pós-doutorado no PPGGI-UFPR. Pesquisador nos grupos de pesquisa InfoMedia (UFPR) e Jararaca (PUC-PR)