Baixando dados do banco de dados do SINAN

[8]:
from pysus.online_data import SINAN, FTP_Inspect, parquets_to_dataframe
import pandas as pd

SINAN é um banco de dados de casos notificados de certas doenças que a lei brasileira exige que sejam reportadas. Infelizmente, os dados disponíveis para download gratuito correspondem apenas aos casos investigados, não à totalidade dos casos reportados. No entanto, é um conjunto de dados interessante.

Para descobrir quais são essas doenças, podemos usar o PySUS:

[2]:
SINAN.list_diseases()
[2]:
['Animais Peçonhentos',
 'Botulismo',
 'Cancer',
 'Chagas',
 'Chikungunya',
 'Colera',
 'Coqueluche',
 'Contact Communicable Disease',
 'Acidentes de Trabalho',
 'Dengue',
 'Difteria',
 'Esquistossomose',
 'Febre Amarela',
 'Febre Maculosa',
 'Febre Tifoide',
 'Hanseniase',
 'Hantavirose',
 'Hepatites Virais',
 'Intoxicação Exógena',
 'Leishmaniose Visceral',
 'Leptospirose',
 'Leishmaniose Tegumentar',
 'Malaria',
 'Meningite',
 'Peste',
 'Poliomielite',
 'Raiva Humana',
 'Sífilis Adquirida',
 'Sífilis Congênita',
 'Sífilis em Gestante',
 'Tétano Acidental',
 'Tétano Neonatal',
 'Tuberculose',
 'Violência Domestica',
 'Zika']

Essas doenças estão disponíveis em tabelas de todo o país, então, se quisermos ver os casos de doença de Chagas no estado de Minas Gerais, primeiro podemos verificar quais anos estão disponíveis:

[3]:
SINAN.get_available_years('Chagas')
[3]:
['2000',
 '2001',
 '2002',
 '2003',
 '2004',
 '2005',
 '2006',
 '2007',
 '2008',
 '2009',
 '2010',
 '2011',
 '2012',
 '2013',
 '2014',
 '2015',
 '2016',
 '2017',
 '2018',
 '2019',
 '2020']

Também podemos verificar quando foi a última atualização para cada doença e se a tabela é preliminar ou final.

[4]:
lu = FTP_Inspect('SINAN').last_update_df()
lu
[4]:
folder date file_size file_name
0 /dissemin/publicos/SINAN/DADOS/FINAIS 2023-01-16 14:15:00 28326 ACBIBR06.dbc
1 /dissemin/publicos/SINAN/DADOS/FINAIS 2023-01-16 14:15:00 673314 ACBIBR07.dbc
2 /dissemin/publicos/SINAN/DADOS/FINAIS 2023-01-16 14:15:00 1048406 ACBIBR08.dbc
3 /dissemin/publicos/SINAN/DADOS/FINAIS 2023-01-16 14:15:00 1493392 ACBIBR09.dbc
4 /dissemin/publicos/SINAN/DADOS/FINAIS 2023-01-16 14:15:00 1632311 ACBIBR10.dbc
... ... ... ... ...
728 /dissemin/publicos/SINAN/DADOS/PRELIM 2023-03-09 16:37:00 169214 VARCBR21.dbc
729 /dissemin/publicos/SINAN/DADOS/PRELIM 2023-03-09 16:37:00 169214 VARCBR22.dbc
730 /dissemin/publicos/SINAN/DADOS/PRELIM 2021-10-15 11:37:00 24793234 VIOLBR20.dbc
731 /dissemin/publicos/SINAN/DADOS/PRELIM 2021-10-15 11:37:00 16021135 VIOLBR21.dbc
732 /dissemin/publicos/SINAN/DADOS/PRELIM 2022-02-23 12:05:00 385559 ZIKABR21.dbc

733 rows × 4 columns

[5]:
lu[lu.file_name.str.startswith('CHAG')]
[5]:
folder date file_size file_name
77 /dissemin/publicos/SINAN/DADOS/FINAIS 2022-03-28 11:18:00 41075 CHAGBR00.dbc
78 /dissemin/publicos/SINAN/DADOS/FINAIS 2022-03-28 11:18:00 47675 CHAGBR01.dbc
79 /dissemin/publicos/SINAN/DADOS/FINAIS 2022-03-28 11:18:00 69415 CHAGBR02.dbc
80 /dissemin/publicos/SINAN/DADOS/FINAIS 2022-03-28 11:18:00 90539 CHAGBR03.dbc
81 /dissemin/publicos/SINAN/DADOS/FINAIS 2022-03-28 11:18:00 86820 CHAGBR04.dbc
82 /dissemin/publicos/SINAN/DADOS/FINAIS 2022-03-28 11:18:00 223289 CHAGBR05.dbc
83 /dissemin/publicos/SINAN/DADOS/FINAIS 2022-03-28 11:18:00 135953 CHAGBR06.dbc
84 /dissemin/publicos/SINAN/DADOS/FINAIS 2021-11-23 12:21:00 11660 CHAGBR07.dbc
85 /dissemin/publicos/SINAN/DADOS/FINAIS 2021-11-23 12:21:00 11004 CHAGBR08.dbc
86 /dissemin/publicos/SINAN/DADOS/FINAIS 2021-11-23 12:21:00 17913 CHAGBR09.dbc
87 /dissemin/publicos/SINAN/DADOS/FINAIS 2021-11-23 12:21:00 13470 CHAGBR10.dbc
88 /dissemin/publicos/SINAN/DADOS/FINAIS 2021-11-23 12:21:00 17109 CHAGBR11.dbc
89 /dissemin/publicos/SINAN/DADOS/FINAIS 2021-11-23 12:21:00 264167 CHAGBR12.dbc
90 /dissemin/publicos/SINAN/DADOS/FINAIS 2021-11-23 12:21:00 245977 CHAGBR13.dbc
91 /dissemin/publicos/SINAN/DADOS/FINAIS 2021-11-23 12:21:00 261115 CHAGBR14.dbc
92 /dissemin/publicos/SINAN/DADOS/FINAIS 2021-11-23 12:21:00 188615 CHAGBR15.dbc
93 /dissemin/publicos/SINAN/DADOS/FINAIS 2022-03-28 11:18:00 244387 CHAGBR16.dbc
94 /dissemin/publicos/SINAN/DADOS/FINAIS 2021-11-23 12:21:00 215819 CHAGBR17.dbc
95 /dissemin/publicos/SINAN/DADOS/FINAIS 2022-03-28 11:18:00 254336 CHAGBR18.dbc
96 /dissemin/publicos/SINAN/DADOS/FINAIS 2021-11-23 12:21:00 285962 CHAGBR19.dbc
522 /dissemin/publicos/SINAN/DADOS/PRELIM 2022-02-09 15:16:00 189312 CHAGBR20.dbc

Podemos ver que temos dados em forma final, de 2000 até 2019, e dados preliminares para 2020. Agora podemos baixá-los:

[9]:
df = parquets_to_dataframe(SINAN.download('Chagas', 2019))
df
[9]:
TP_NOT ID_AGRAVO DT_NOTIFIC SEM_NOT NU_ANO SG_UF_NOT ID_MUNICIP ID_REGIONA ID_UNIDADE DT_SIN_PRI ... DT_OBITO CON_PROVAV CON_OUTRA CON_LOCAL TPAUTOCTO COUFINF COPAISINF COMUNINF DOENCA_TRA DT_ENCERRA
0 2 B571 2019-04-10 201915 2019 16 160030 2019639 2019-03-01 ... 5 2 1 16 1 160030 2 20190513
1 2 B571 2019-09-16 201938 2019 16 160030 2022192 2019-08-18 ... 5 2 2 16 1 160060 2 20191002
2 2 B571 2019-03-07 201910 2019 16 160030 2022192 2019-02-28 ... 5 2 1 16 1 160030 20190325
3 2 B571 2019-10-22 201943 2019 16 160030 2020653 2019-09-09 ... 5 2 1 16 1 160030 2 20191107
4 2 B571 2019-09-10 201937 2019 16 160060 2020971 2019-08-28 ... 5 2 1 16 1 160060 2 20191108
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
4477 2 B571 2019-09-05 201936 2019 26 260120 1501 5740592 2019-09-04 ... 0 20191022
4478 2 B571 2019-09-26 201939 2019 26 261390 1506 2348489 2019-08-26 ... 2 2 1 26 1 261390 2 20191008
4479 2 B571 2019-01-17 201903 2019 26 260120 1501 2711443 2019-01-05 ... 0 20190212
4480 2 B571 2019-07-03 201927 2019 26 260820 1498 5276403 2019-07-03 ... 0 20190903
4481 2 B571 2019-11-08 201945 2019 26 261220 1502 5844916 2019-08-04 ... 0 20200124

4482 rows × 99 columns

Baixando arquivos grandes

Alguns arquivos do SINAN podem ser bastante grandes e podem demorar um pouco mais para serem baixados e convertidos. Como o comportamento padrão é baixar dados em blocos, algumas pastas podem conter muitos pedaços de parquet.

[13]:
fn = SINAN.download('Dengue', 2020)

Os casos de dengue foram baixados em vários pedaços para o diretório acima

[15]:
import os
len(os.listdir(fn))
[15]:
50
[18]:
df2 = parquets_to_dataframe(fn)
len(df2)
[18]:
1495117

Decodificando a idade nas tabelas do SINAN

No SINAN, a idade vem codificada. O PySUS pode decodificar a coluna de idade NU_IDADE_N em qualquer uma dessas unidades: anos, meses, dias ou horas.

[ ]:
from glob import glob
for i, f in enumerate(glob(f"{fn}/*.parquet")):
    if i == 0:
        df2 = pd.read_parquet(f)
    else:
        df2 = pd.concat([df2, pd.read_parquet(f)], ignore_index=True)
df2
TP_NOT ID_AGRAVO DT_NOTIFIC SEM_NOT NU_ANO SG_UF_NOT ID_MUNICIP ID_REGIONA ID_UNIDADE DT_SIN_PRI ... LACO_N PLASMATICO EVIDENCIA PLAQ_MENOR CON_FHD COMPLICA TP_SISTEMA NDUPLIC_N CS_FLXRET FLXRECEBI
0 2 A90 2020-06-03 2020 50 500660 1972 5870178 2020-06-01 ... 2 0
1 2 A90 2020-04-02 2020 50 500660 1972 2651610 2020-03-31 ... 2 0
2 2 A90 2020-05-31 2020 50 500660 1972 2651610 2020-05-30 ... 2 0
3 2 A90 2020-09-05 2020 50 500660 1972 2651610 2020-08-29 ... 2 0
4 2 A90 2020-04-25 2020 50 500660 1972 5870178 2020-04-24 ... 2 0
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1495112 2 A90 2020-01-28 2020 32 320530 1510 2675110 2020-01-27 ... 2 0
1495113 2 A90 2020-02-20 2020 32 320530 1510 0012173 2020-02-18 ... 2 0
1495114 2 A90 2020-03-02 2020 32 320530 1510 0012173 2020-02-23 ... 2 0
1495115 2 A90 2020-02-17 2020 32 320530 1510 0028177 2020-02-05 ... 2 0
1495116 2 A90 2020-03-04 2020 32 320530 1510 0012173 2020-01-31 ... 2 0

1495117 rows × 119 columns

Decodificando a idade nas tabelas do SINAN

No SINAN, a idade vem codificada. O PySUS pode decodificar a coluna de idade NU_IDADE_N em qualquer uma dessas unidades: anos, meses, dias ou horas.

[19]:
from pysus.preprocessing.decoders import decodifica_idade_SINAN
decodifica_idade_SINAN?
Signature:       decodifica_idade_SINAN(*args, **kwargs)
Type:            vectorize
String form:     <numpy.vectorize object at 0x7fe908e44b20>
File:            ~/micromamba/envs/pysus/lib/python3.9/site-packages/numpy/__init__.py
Docstring:
Em tabelas do SINAN frequentemente a idade é representada como um inteiro que precisa ser parseado
para retornar a idade em uma unidade cronológica padrão.
:param unidade: unidade da idade: 'Y': anos, 'M' meses, 'D': dias, 'H': horas
:param idade: inteiro ou sequencia de inteiros codificados.
:return:
Class docstring:
vectorize(pyfunc, otypes=None, doc=None, excluded=None, cache=False,
          signature=None)

Generalized function class.

Define a vectorized function which takes a nested sequence of objects or
numpy arrays as inputs and returns a single numpy array or a tuple of numpy
arrays. The vectorized function evaluates `pyfunc` over successive tuples
of the input arrays like the python map function, except it uses the
broadcasting rules of numpy.

The data type of the output of `vectorized` is determined by calling
the function with the first element of the input.  This can be avoided
by specifying the `otypes` argument.

Parameters
----------
pyfunc : callable
    A python function or method.
otypes : str or list of dtypes, optional
    The output data type. It must be specified as either a string of
    typecode characters or a list of data type specifiers. There should
    be one data type specifier for each output.
doc : str, optional
    The docstring for the function. If None, the docstring will be the
    ``pyfunc.__doc__``.
excluded : set, optional
    Set of strings or integers representing the positional or keyword
    arguments for which the function will not be vectorized.  These will be
    passed directly to `pyfunc` unmodified.

    .. versionadded:: 1.7.0

cache : bool, optional
    If `True`, then cache the first function call that determines the number
    of outputs if `otypes` is not provided.

    .. versionadded:: 1.7.0

signature : string, optional
    Generalized universal function signature, e.g., ``(m,n),(n)->(m)`` for
    vectorized matrix-vector multiplication. If provided, ``pyfunc`` will
    be called with (and expected to return) arrays with shapes given by the
    size of corresponding core dimensions. By default, ``pyfunc`` is
    assumed to take scalars as input and output.

    .. versionadded:: 1.12.0

Returns
-------
vectorized : callable
    Vectorized function.

See Also
--------
frompyfunc : Takes an arbitrary Python function and returns a ufunc

Notes
-----
The `vectorize` function is provided primarily for convenience, not for
performance. The implementation is essentially a for loop.

If `otypes` is not specified, then a call to the function with the
first argument will be used to determine the number of outputs.  The
results of this call will be cached if `cache` is `True` to prevent
calling the function twice.  However, to implement the cache, the
original function must be wrapped which will slow down subsequent
calls, so only do this if your function is expensive.

The new keyword argument interface and `excluded` argument support
further degrades performance.

References
----------
.. [1] :doc:`/reference/c-api/generalized-ufuncs`

Examples
--------
>>> def myfunc(a, b):
...     "Return a-b if a>b, otherwise return a+b"
...     if a > b:
...         return a - b
...     else:
...         return a + b

>>> vfunc = np.vectorize(myfunc)
>>> vfunc([1, 2, 3, 4], 2)
array([3, 4, 1, 2])

The docstring is taken from the input function to `vectorize` unless it
is specified:

>>> vfunc.__doc__
'Return a-b if a>b, otherwise return a+b'
>>> vfunc = np.vectorize(myfunc, doc='Vectorized `myfunc`')
>>> vfunc.__doc__
'Vectorized `myfunc`'

The output type is determined by evaluating the first element of the input,
unless it is specified:

>>> out = vfunc([1, 2, 3, 4], 2)
>>> type(out[0])
<class 'numpy.int64'>
>>> vfunc = np.vectorize(myfunc, otypes=[float])
>>> out = vfunc([1, 2, 3, 4], 2)
>>> type(out[0])
<class 'numpy.float64'>

The `excluded` argument can be used to prevent vectorizing over certain
arguments.  This can be useful for array-like arguments of a fixed length
such as the coefficients for a polynomial as in `polyval`:

>>> def mypolyval(p, x):
...     _p = list(p)
...     res = _p.pop(0)
...     while _p:
...         res = res*x + _p.pop(0)
...     return res
>>> vpolyval = np.vectorize(mypolyval, excluded=['p'])
>>> vpolyval(p=[1, 2, 3], x=[0, 1])
array([3, 6])

Positional arguments may also be excluded by specifying their position:

>>> vpolyval.excluded.add(0)
>>> vpolyval([1, 2, 3], x=[0, 1])
array([3, 6])

The `signature` argument allows for vectorizing functions that act on
non-scalar arrays of fixed length. For example, you can use it for a
vectorized calculation of Pearson correlation coefficient and its p-value:

>>> import scipy.stats
>>> pearsonr = np.vectorize(scipy.stats.pearsonr,
...                 signature='(n),(n)->(),()')
>>> pearsonr([[0, 1, 2, 3]], [[1, 2, 3, 4], [4, 3, 2, 1]])
(array([ 1., -1.]), array([ 0.,  0.]))

Or for a vectorized convolution:

>>> convolve = np.vectorize(np.convolve, signature='(n),(m)->(k)')
>>> convolve(np.eye(4), [1, 2, 1])
array([[1., 2., 1., 0., 0., 0.],
       [0., 1., 2., 1., 0., 0.],
       [0., 0., 1., 2., 1., 0.],
       [0., 0., 0., 1., 2., 1.]])
Call docstring:
Return arrays with the results of `pyfunc` broadcast (vectorized) over
`args` and `kwargs` not in `excluded`.

Podemos facilmente converter datas e campos numéricos no dataframe:

[20]:
for cname in df.columns:
    if cname.startswith('DT_'):
        df[cname] = pd.to_datetime(df[cname], errors='coerce')
    elif cname.startswith('ID_'):
        try:
            df[cname] = pd.to_numeric(df[cname])
        except ValueError:
            continue
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4482 entries, 0 to 4481
Data columns (total 99 columns):
 #   Column      Non-Null Count  Dtype
---  ------      --------------  -----
 0   TP_NOT      4482 non-null   string
 1   ID_AGRAVO   4482 non-null   string
 2   DT_NOTIFIC  4482 non-null   datetime64[ns]
 3   SEM_NOT     4482 non-null   string
 4   NU_ANO      4482 non-null   string
 5   SG_UF_NOT   4482 non-null   string
 6   ID_MUNICIP  4482 non-null   int64
 7   ID_REGIONA  3633 non-null   float64
 8   ID_UNIDADE  4482 non-null   int64
 9   DT_SIN_PRI  4482 non-null   datetime64[ns]
 10  SEM_PRI     4482 non-null   string
 11  DT_NASC     4447 non-null   datetime64[ns]
 12  NU_IDADE_N  4482 non-null   string
 13  CS_SEXO     4482 non-null   string
 14  CS_GESTANT  4482 non-null   string
 15  CS_RACA     4482 non-null   string
 16  CS_ESCOL_N  4482 non-null   string
 17  SG_UF       4482 non-null   string
 18  ID_MN_RESI  4482 non-null   int64
 19  ID_RG_RESI  3682 non-null   float64
 20  ID_PAIS     4482 non-null   int64
 21  NDUPLIC_N   4482 non-null   string
 22  DT_INVEST   4329 non-null   datetime64[ns]
 23  ID_OCUPA_N  4482 non-null   string
 24  ANT_UF_1    4482 non-null   string
 25  MUN_1       4482 non-null   string
 26  ANT_UF_2    4482 non-null   string
 27  MUN_2       4482 non-null   string
 28  ANT_UF_3    4482 non-null   string
 29  MUN_3       4482 non-null   string
 30  PRESENCA    4482 non-null   string
 31  PARASITO    4482 non-null   string
 32  HISTORIA    4482 non-null   string
 33  CONTROLE    4482 non-null   string
 34  MANIPULA    4482 non-null   string
 35  MAECHAGA    4482 non-null   string
 36  ORAL        4482 non-null   string
 37  ASSINTOMA   4482 non-null   string
 38  EDEMA       4482 non-null   string
 39  MENINGOE    4482 non-null   string
 40  POLIADENO   4482 non-null   string
 41  FEBRE       4482 non-null   string
 42  HEPATOME    4482 non-null   string
 43  SINAIS_ICC  4482 non-null   string
 44  ARRITMIAS   4482 non-null   string
 45  ASTENIA     4482 non-null   string
 46  ESPLENOM    4482 non-null   string
 47  CHAGOMA     4482 non-null   string
 48  OUTRO_SIN   4482 non-null   string
 49  OUTRO_ESP   4482 non-null   string
 50  DT_COL_DIR  2693 non-null   datetime64[ns]
 51  EXAME       4482 non-null   string
 52  MICRO_HEMA  4482 non-null   string
 53  OUTRO       4482 non-null   string
 54  DT_COL_IND  155 non-null    datetime64[ns]
 55  XENODIAG    4482 non-null   string
 56  HEMOCULT    4482 non-null   string
 57  DT_COL_S1   3300 non-null   datetime64[ns]
 58  DT_COL_S2   790 non-null    datetime64[ns]
 59  ELI_IGM_S1  4482 non-null   string
 60  ELI_IGG_S1  4482 non-null   string
 61  ELI_IGM_S2  4482 non-null   string
 62  ELI_IGG_S2  4482 non-null   string
 63  HEM_IGM_S1  4482 non-null   string
 64  HEM_IGG_S1  4482 non-null   string
 65  HEM_IGM_S2  4482 non-null   string
 66  HEM_IGG_S2  4482 non-null   string
 67  IMU_IGM_S1  4482 non-null   string
 68  TIT_IGM_S1  4482 non-null   string
 69  IMU_IGM_S2  4482 non-null   string
 70  TIT_IGM_S2  4482 non-null   string
 71  IMU_IGG_S1  4482 non-null   string
 72  TIT_IGG_S1  4482 non-null   string
 73  IMU_IGG_S2  4482 non-null   string
 74  TIT_IGG_S2  4482 non-null   string
 75  RESUL_HIS   4482 non-null   string
 76  RES_HIST    4482 non-null   string
 77  ESPECIFICO  4482 non-null   string
 78  SINTOMATIC  4482 non-null   string
 79  DROGA       4482 non-null   string
 80  TEMPO       4482 non-null   string
 81  CON_TRIAT   4482 non-null   string
 82  BIOSSEG     4482 non-null   string
 83  FISCALIZA   4482 non-null   string
 84  MED_OUTRO   4482 non-null   string
 85  OUTRO_DES   4482 non-null   string
 86  CLASSI_FIN  4482 non-null   string
 87  CRITERIO    4482 non-null   string
 88  EVOLUCAO    4482 non-null   string
 89  DT_OBITO    54 non-null     datetime64[ns]
 90  CON_PROVAV  4482 non-null   string
 91  CON_OUTRA   4482 non-null   string
 92  CON_LOCAL   4482 non-null   string
 93  TPAUTOCTO   4482 non-null   string
 94  COUFINF     4482 non-null   string
 95  COPAISINF   4482 non-null   string
 96  COMUNINF    4482 non-null   string
 97  DOENCA_TRA  4482 non-null   string
 98  DT_ENCERRA  4366 non-null   datetime64[ns]
dtypes: datetime64[ns](10), float64(2), int64(4), string(83)
memory usage: 3.4 MB

Vamos converter a idade para anos e salvá-la em uma coluna diferente.

[21]:
df['idade_anos'] = decodifica_idade_SINAN(df.NU_IDADE_N, 'Y')
df[['NU_IDADE_N', 'idade_anos']]
[21]:
NU_IDADE_N idade_anos
0 4013 13.0
1 4054 54.0
2 4031 31.0
3 4063 63.0
4 4036 36.0
... ... ...
4477 4079 79.0
4478 4063 63.0
4479 4039 39.0
4480 4036 36.0
4481 4052 52.0

4482 rows × 2 columns

Salvando os dados modificados

Pode-se salvar nosso conjunto de dados em qualquer formato que desejarmos para evitar ter que refazer esta análise na próxima vez. Se quisermos manter apenas os dados do estado de Minas Gerais, precisamos filtrar a tabela usando o código UF 31.

[22]:
df['SG_UF_NOT'] = df.SG_UF_NOT.astype(int)
df[df.SG_UF_NOT==31].to_csv('chagas_SP_2018_mod.csv',sep=';',compression='zip')
[ ]: