Análise Epidemiológica de Óbitos: Explorando Padrões e Tendências para Informar Políticas de Saúde Pública

Luciano Magalhães Luciano Magalhães   |   schedule Dezembro, 2023  |   view_object_track Machine Learning

1. Descrição Geral do Problema¶

Imagem de Detecção de Fraude

Em um hospital, os administradores estão preocupados com o aumento do número de óbitos de pacientes devido a doenças crônicas. Eles desejam implementar medidas preventivas e intervenções precoces para melhorar os resultados dos pacientes.

O hospital deseja identificar padrões e fatores de risco associados à mortalidade por doenças crônicas com base nos dados disponíveis, a fim de desenvolver estratégias de intervenção mais eficazes.

1. Contexto¶

Em um hospital, os administradores estão preocupados com o aumento do número de óbitos de pacientes devido a doenças crônicas. Eles desejam implementar medidas preventivas e intervenções precoces para melhorar os resultados dos pacientes.

2. Problema proposto¶

O hospital deseja identificar padrões e fatores de risco associados à mortalidade por doenças crônicas com base nos dados disponíveis, a fim de desenvolver estratégias de intervenção mais eficazes.

# Pergunta Descrição
1 Quem? Pacientes do hospital, equipe médica e administradores
2 O que? Identificar padrões e fatores de risco associados à mortalidade por doenças crônicas
3 Onde? Ambiente hospitalar
4 Quando? Análise contínua para monitorar padrões de mortalidade e ajustar intervenções conforme necessário
5 Por que? Desenvolver estratégias de intervenção para melhorar os resultados e qualidade de vida dos pacientes com doenças crônicas

3. Carregando Dados¶

Os dados analisados são dados públicos do portal dados.gov.br, referentes ao Estado de Minas Gerais no ano de 2022.


3.1. Importação das Bibliotecas de Interesse¶

Começaremos importanto todas as bilbiotecas necessárias, para a realização das fases iniciais de exploração, e transformação dos dados (Data Munging).

In [3]:
# Importando biblioteca, para ocultar Future Warnings.

import warnings

warnings.simplefilter(action = 'ignore', category = FutureWarning)

# Importando bibliotecas, para a manipulação e exploração dos conjuntos de dados.

import numpy as np

import pandas as pd

# Importando bibliotecas, para a plotagem de gráficos interativos com o plotly.

import plotly.offline as py

import plotly.graph_objs as go

import plotly.figure_factory as ff

py.init_notebook_mode(connected = False)

# Importando bibliotecas, para a plotagem de gráficos com o Seaborn e Matplotlib.

import seaborn as sns

import matplotlib.pyplot as plt

# train_test_split é utilizada para dividir os dados em conjuntos de treinamento e teste
from sklearn.model_selection import train_test_split 
        
#RandomForestClassifier: Modelo para classificação em dados complexos, reduz risco de overfitting.
from sklearn.ensemble import RandomForestClassifier  

# accuracy_score: Mede a precisão das previsões do modelo.
from sklearn.metrics import accuracy_score

# LabelEncoder: Converte rótulos de texto em valores numéricos para análise.
from sklearn.preprocessing import LabelEncoder

from datetime import datetime, timedelta

from sklearn.impute import SimpleImputer

from IPython.display import display, Markdown, HTML

import os

import warnings
warnings.filterwarnings("ignore")

Carregar dados¶

In [4]:
# Carregamento de dados
try:
    dados_obito_doenca_cronica = pd.read_csv('dados_obitos_cronicas.csv', delimiter=';', encoding='utf-8')
    display(Markdown("<h3 style='color: darkred'>Dados carregados com sucesso!!</h3>"))
except FileNotFoundError:
    display(Markdown("<h3 style='color: darkred'>Não foi possível carregar o arquivo!!</h3>"))

Dados carregados com sucesso!!


5. Análise Exploratória de Dados¶


5.1 Exibindo as Primeiras Linhas do Dataset Carregado¶

In [3]:
dados_obito_doenca_cronica.head()
Out[3]:
dt_obito dt_nascimento nu_idade sg_sexo tp_raca_cor tp_escolaridade co_municipio_ibge_residencia co_municipio_ibge_ocorrencia co_cid_causa_basica desc_cid_causa_basica capitulo_cid_causa_basica categoria_cid_causa_basica
0 01/01/2022 05/03/1942 79.0 Feminino Branca de 4 a 7 anos Belo Horizonte Belo Horizonte C069 BOCA NE II. NEOPLASIAS (TUMORES) NEOPL MALIG OUTR PARTES E PARTES NE DA BOCA
1 01/01/2022 14/08/1969 52.0 Masculino Branca de 1 a 3 anos Itatiaiuçu Itatiaiuçu C069 BOCA NE II. NEOPLASIAS (TUMORES) NEOPL MALIG OUTR PARTES E PARTES NE DA BOCA
2 01/01/2022 23/08/1947 74.0 Masculino Branca de 8 a 11 anos Nanuque Nanuque C169 ESTOMAGO NE II. NEOPLASIAS (TUMORES) NEOPL MALIG DO ESTOMAGO
3 01/01/2022 19/07/1968 53.0 Masculino Parda de 4 a 7 anos Ribeirão das Neves Ribeirão das Neves C169 ESTOMAGO NE II. NEOPLASIAS (TUMORES) NEOPL MALIG DO ESTOMAGO
4 01/01/2022 28/03/1946 75.0 Feminino Parda Ignorado Belo Horizonte Belo Horizonte C169 ESTOMAGO NE II. NEOPLASIAS (TUMORES) NEOPL MALIG DO ESTOMAGO

5.2. Visão Geral dos Dados¶

In [4]:
# Exibindo informações da quantidade de registros e colunas 

display(Markdown(f"<h3 style='color: darkblue'> Existem {dados_obito_doenca_cronica.shape[0]} observações e {dados_obito_doenca_cronica.shape[1]} colunas no DataSet. "))

Existem 82308 observações e 12 colunas no DataSet.


5.3. Metadados de Cada Variável:¶

Variável Tipo Descrição
dt_obito object Data de óbito
dt_nascimento object Data de nascimento do paciente
nu_idade float64 Idade do paciente em anos
sg_sexo object Sexo do paciente (Masculino/Feminino)
tp_raca_cor object Raça/cor do paciente
tp_escolaridade object Escolaridade do paciente
co_municipio_ibge_residencia object Código IBGE do município de residência
co_municipio_ibge_ocorrencia object Código IBGE do município de ocorrência do óbito
co_cid_causa_basica object Código CID da causa básica do óbito
desc_cid_causa_basica object Descrição da causa básica do óbito
capitulo_cid_causa_basica object Capítulo da CID da causa básica do óbito
categoria_cid_causa_basica object Categoria da CID da causa básica do óbito

5.4. Contabilizando o Número de Valores Únicos em Cada Variável¶

In [5]:
# Calculando valores únicos e classificando em ordem crescente

calc_dados_unicos = dados_obito_doenca_cronica.nunique().sort_values() 

# Determinando o tipo de dado de cada uma das variáveis do dataset.

calc_dados_unicos = pd.DataFrame(calc_dados_unicos.values, index = calc_dados_unicos.index, columns = ['Valor_unico'])

# Atribuindo informações sobre o tipo de dado das variáveis ao DataFrame.

calc_dados_unicos['Tipo'] = dados_obito_doenca_cronica.dtypes

# Exibindo Dataframe.

calc_dados_unicos
Out[5]:
Valor_unico Tipo
sg_sexo 2 object
tp_raca_cor 5 object
capitulo_cid_causa_basica 5 object
tp_escolaridade 6 object
nu_idade 117 float64
categoria_cid_causa_basica 196 object
dt_obito 365 object
desc_cid_causa_basica 758 object
co_cid_causa_basica 787 object
co_municipio_ibge_ocorrencia 841 object
co_municipio_ibge_residencia 853 object
dt_nascimento 22175 object

5.5. Análise de dados faltantes¶

In [6]:
# Calcula o total e a porcentagem de dados faltantes por coluna

total_faltantes = dados_obito_doenca_cronica.isnull().sum()
percentual_faltantes = (dados_obito_doenca_cronica.isnull().mean() * 100)

# Criar um DataFrame para a tabela resumida

tabela_resumo_faltantes = pd.DataFrame({
    'Coluna': total_faltantes.index,
    'Dados Faltantes': total_faltantes.values,
    'Percentual (%)': percentual_faltantes.values
})

# Ordenar a tabela pelo número de dados faltantes

tabela_resumo_faltantes = tabela_resumo_faltantes.sort_values(by='Dados Faltantes', ascending=False)

display(Markdown("<h3 style='color: darkblue'>Tabela Resumo de Dados Faltantes</h3>"))

# Exibi a tabela resumida

print(tabela_resumo_faltantes)

Tabela Resumo de Dados Faltantes

                          Coluna  Dados Faltantes  Percentual (%)
5                tp_escolaridade             4326        5.255868
4                    tp_raca_cor             1377        1.672984
7   co_municipio_ibge_ocorrencia              959        1.165136
6   co_municipio_ibge_residencia              468        0.568596
1                  dt_nascimento               35        0.042523
9          desc_cid_causa_basica               21        0.025514
2                       nu_idade                8        0.009720
0                       dt_obito                0        0.000000
3                        sg_sexo                0        0.000000
8            co_cid_causa_basica                0        0.000000
10     capitulo_cid_causa_basica                0        0.000000
11    categoria_cid_causa_basica                0        0.000000

5.6. Imputação de Dados Faltantes¶

No contexto do projeto hospitalar, a imputação de dados é fundamental para manter a integridade do dataset, permitindo análises mais completas e reduzindo o viés potencial causado por dados faltantes.

In [7]:
#*************************************************************************************************

from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
from sklearn.ensemble import RandomForestRegressor

# imputação de 'nu_idade'

imputacao = IterativeImputer(estimator=RandomForestRegressor(), initial_strategy='median', max_iter=10, random_state=0)
dados_obito_doenca_cronica[['nu_idade']] = imputacao.fit_transform(dados_obito_doenca_cronica[['nu_idade']])

#*************************************************************************************************

# imputação data de nascimento

with warnings.catch_warnings():  # Cria um contexto que permite capturar os avisos que são emitidos dentro do bloco de código.
    warnings.simplefilter("ignore") # cria um filtro "ignore" para ignorar todos avisos ao usuário
    
    
    # Função para converter data de nascimento, tratando valores inválidos
    
    def converter_data(data_str):
        try:
            
            return pd.to_datetime(data_str, format='%d/%m/%Y')
        
        except (ValueError, TypeError):
            
            return pd.NaT

    # Trata os registros faltantes da dt_nascimento pelo calculo da idade registrada com a data atual

    # Identificando registros onde 'dt_nascimento' está faltando
    registros_sem_dt_nascimento = dados_obito_doenca_cronica[dados_obito_doenca_cronica['dt_nascimento'].isna()]

    # Calculando as datas de nascimento utilizando 'nu_idade' e a data atual
    data_atual = datetime.now()

    registros_sem_dt_nascimento['dt_nascimento'] = data_atual - registros_sem_dt_nascimento['nu_idade'].apply(lambda x: timedelta(days=365.25*x))

    dados_obito_doenca_cronica.loc[registros_sem_dt_nascimento.index, 'dt_nascimento'] = data_atual - registros_sem_dt_nascimento['nu_idade'].apply(lambda x: timedelta(days=365.25*x))

    # Converte os valores de 'dt_nascimento' usando a função converter_data
    
    dados_obito_doenca_cronica['dt_nascimento'] = dados_obito_doenca_cronica['dt_nascimento'].apply(converter_data)


#*************************************************************************************************

# Demais imputação
# Imputação para variáveis categóricas ('tp_escolaridade', 'tp_raca_cor') 
imputer_cat = SimpleImputer(strategy='most_frequent')
dados_obito_doenca_cronica[['tp_escolaridade', 'tp_raca_cor']] = imputer_cat.fit_transform(dados_obito_doenca_cronica[['tp_escolaridade', 'tp_raca_cor']])

# Para 'co_municipio_ibge_ocorrencia' e 'co_municipio_ibge_residencia', imputar um valor específico
dados_obito_doenca_cronica['co_municipio_ibge_ocorrencia'].fillna('999999', inplace=True)
dados_obito_doenca_cronica['co_municipio_ibge_residencia'].fillna('999999', inplace=True)

#*************************************************************************************************

5.7. Carregando Dados de CID para Encontrar e Preencher dados Faltantes na variável desc_cid_causa_basica¶

In [8]:
try:
    dados_cid = pd.read_csv('CID-10-SUBCATEGORIAS.csv', delimiter=';', encoding='ISO-8859-1')
    display(Markdown("<h3 style='color: darkred'>Dados carregados com sucesso!!</h3>"))
except FileNotFoundError:
    display(Markdown("<h3 style='color: darkred'>Não foi possível carregar o arquivo!!</h3>"))

Dados carregados com sucesso!!


5.8. Exibindo as Primeiras Linhas do Dataset CID¶

In [9]:
dados_cid.head()
Out[9]:
SUBCAT CLASSIF RESTRSEXO CAUSAOBITO DESCRICAO DESCRABREV REFER EXCLUIDOS Unnamed: 8
0 A000 NaN NaN NaN Cólera devida a Vibrio cholerae 01, biótipo ch... A00.0 Colera dev Vibrio cholerae 01 biot cholerae NaN NaN NaN
1 A001 NaN NaN NaN Cólera devida a Vibrio cholerae 01, biótipo El... A00.1 Colera dev Vibrio cholerae 01 biot El Tor NaN NaN NaN
2 A009 NaN NaN NaN Cólera não especificada A00.9 Colera NE NaN NaN NaN
3 A010 NaN NaN NaN Febre tifóide A01.0 Febre tifoide NaN NaN NaN
4 A011 NaN NaN NaN Febre paratifóide A A01.1 Febre paratifoide A NaN NaN NaN

5.9. Fusão dos Dados 'dados_obito_doenca_cronica' e 'dados_cid' e Preenchimento dos Valores Ausentes na coluna 'desc_cid_causa_basica'¶

No código abaixo estaremos usando outra base de dados que consta as informações a respeito da Classificação Internacional de Doenças - CID, para que dados ausentes sobre descrição CID sejam preenchidas.

In [10]:
# Renomear a coluna 'co_cid_causa_basica' para 'SUBCAT' no DataFrame 'dados_obito_doenca_cronica'
dados_obito_doenca_cronica.rename(columns={'co_cid_causa_basica': 'SUBCAT'}, inplace=True)

# Mesclar os DataFrames e preencher valores nulos
merged_data = pd.merge(dados_obito_doenca_cronica, dados_cid[['SUBCAT', 'DESCRICAO']], on='SUBCAT', how='left')
merged_data['desc_cid_causa_basica'].fillna(merged_data['DESCRICAO'], inplace=True)

# Atualizar a coluna 'desc_cid_causa_basica' na base de dados original 'dados_obito_doenca_cronica'
dados_obito_doenca_cronica['desc_cid_causa_basica'] = merged_data['desc_cid_causa_basica']

5.10. Analise de Dados Faltantes após Imputações¶

In [11]:
# Calcula o total e a porcentagem de dados faltantes por coluna
total_faltantes = dados_obito_doenca_cronica.isnull().sum()
percentual_faltantes = (dados_obito_doenca_cronica.isnull().mean() * 100)

# Criar um DataFrame para a tabela resumida
tabela_resumo_faltantes = pd.DataFrame({
    'Coluna': total_faltantes.index,
    'Dados Faltantes': total_faltantes.values,
    'Percentual (%)': percentual_faltantes.values
})

# Ordenar a tabela pelo número de dados faltantes
tabela_resumo_faltantes = tabela_resumo_faltantes.sort_values(by='Dados Faltantes', ascending=False)

# Exibir um título estilizado para a tabela resumida
display(Markdown("<h3 style='color: darkblue'>Tabela Resumo de Dados Faltantes</h3>"))

# Exibir a tabela resumida
print(tabela_resumo_faltantes)

Tabela Resumo de Dados Faltantes

                          Coluna  Dados Faltantes  Percentual (%)
0                       dt_obito                0             0.0
1                  dt_nascimento                0             0.0
2                       nu_idade                0             0.0
3                        sg_sexo                0             0.0
4                    tp_raca_cor                0             0.0
5                tp_escolaridade                0             0.0
6   co_municipio_ibge_residencia                0             0.0
7   co_municipio_ibge_ocorrencia                0             0.0
8                         SUBCAT                0             0.0
9          desc_cid_causa_basica                0             0.0
10     capitulo_cid_causa_basica                0             0.0
11    categoria_cid_causa_basica                0             0.0

5.11. Verificação e Tratamento de Dados Duplicados¶

In [12]:
import pandas as pd
from IPython.display import Markdown, display

# Conta o número de registros duplicados
numero_duplicados = dados_obito_doenca_cronica.duplicated().sum()

# Calcula a porcentagem de duplicatas em relação ao total
total_registros = len(dados_obito_doenca_cronica)
percentual_duplicados = (numero_duplicados / total_registros) * 100

if numero_duplicados > 0: 
    display(Markdown(f"<h3 style='color: darkred'>Foram encontrados {numero_duplicados} registros duplicados, representando {percentual_duplicados:.2f}% do total de {dados_obito_doenca_cronica.shape[0]} registros!</h3>")) 

    # Removendo registros duplicados do DataFrame
    dados_obito_doenca_cronica = dados_obito_doenca_cronica.drop_duplicates()
    
    # Verificando se há registros duplicados após a remoção
    numero_duplicados_apos_remocao = dados_obito_doenca_cronica.duplicated().sum()

    if numero_duplicados_apos_remocao > 0: 
        print("\nAinda há", numero_duplicados_apos_remocao, "registros duplicados após a remoção.")
        print("Isso pode indicar que alguns registros eram duplicados parciais.")
    else:
        display(Markdown("<h3 style='color: darkred'>Registros duplicados excluídos! </h3>")) 

else: 
    display(Markdown("<h2 style='color: red'>Não foram encontrados dados duplicados no conjunto de dados</h2>"))

Foram encontrados 5 registros duplicados, representando 0.01% do total de 82308 registros!

Registros duplicados excluídos!


5.12. Ajuste no Tipo de Dados das Variáveis para Proseguimento das Análises¶

In [13]:
dados_obito_doenca_cronica['dt_obito'] = pd.to_datetime(dados_obito_doenca_cronica['dt_obito'], format='%d/%m/%Y')
dados_obito_doenca_cronica['dt_nascimento'] = pd.to_datetime(dados_obito_doenca_cronica['dt_nascimento'], format='%d/%m/%Y')

dados_obito_doenca_cronica['sg_sexo'] = dados_obito_doenca_cronica['sg_sexo'].astype('category')
dados_obito_doenca_cronica['tp_raca_cor'] = dados_obito_doenca_cronica['tp_raca_cor'].astype('category')
dados_obito_doenca_cronica['tp_escolaridade'] = dados_obito_doenca_cronica['tp_escolaridade'].astype('category')

dados_obito_doenca_cronica['nu_idade'] = dados_obito_doenca_cronica['nu_idade'].astype('int')

# apresenta a modificação
display(Markdown("<h3 style='color: darkblue'>Variavéis Após Modificações de Tipo de Dados</h3>"))
dados_obito_doenca_cronica.dtypes

Variavéis Após Modificações de Tipo de Dados

Out[13]:
dt_obito                        datetime64[ns]
dt_nascimento                   datetime64[ns]
nu_idade                                 int32
sg_sexo                               category
tp_raca_cor                           category
tp_escolaridade                       category
co_municipio_ibge_residencia            object
co_municipio_ibge_ocorrencia            object
SUBCAT                                  object
desc_cid_causa_basica                   object
capitulo_cid_causa_basica               object
categoria_cid_causa_basica              object
dtype: object

5.13. Apresenta gráfico com Distribuição de Idade dos Pacientes¶

In [15]:
#******************************************************************************
# gráfico Distribuição de Idade dos Pacientes
#

# Configurando o tamanho do gráfico
plt.figure(figsize=(10, 6))

# criando o histograma
histograma = sns.histplot(dados_obito_doenca_cronica['nu_idade'], kde=True, bins=30, color='lightblue')

# configurando a linha do KDE para ser vermelha
kde_color = 'red'
for l in histograma.lines:
    l.set_color(kde_color)

# Ajustando o título e os rótulos dos eixos com espaçamento adicional para o título
print("\n")
plt.title('Distribuição de Idade dos Pacientes que Faleceram', fontsize=18, pad=20)   #pad define valor para espaçamento
plt.xlabel('Idade', fontsize=14, labelpad=20)
plt.ylabel('Número de Pacientes', fontsize=14, labelpad=20)
           
# Definindo os valores do eixo x
valores_x = range(0, 121, 10)  # de 0 a 120 com intervalo de 10
plt.xticks(valores_x)

# apresentar os valores acima das barras com uma ligeira rotação e deslocamento vertical aumentado
for p in histograma.patches:
    histograma.annotate(f'{int(p.get_height())}', (p.get_x() + p.get_width() / 2., p.get_height()), 
                 ha='center', va='center', fontsize=11, color='black', xytext=(1, 18), 
                 textcoords='offset points', rotation=80)
    
# ajustamos os limites do eixo y para aumentar o espaço acima da barra mais alta
max_height = max([p.get_height() for p in histograma.patches])
histograma.set_ylim(0, max_height * 1.27)  # valor para aumentar o limite superior para criar mais espaço

# Mostrando o gráfico
plt.show()

No description has been provided for this image

5.14. Estatística Descritiva da Idade¶

In [16]:
# Descrição estatística básica
descricao_estatistica = dados_obito_doenca_cronica['nu_idade'].describe()

# Mediana
mediana = dados_obito_doenca_cronica['nu_idade'].median()

# Moda
moda = dados_obito_doenca_cronica['nu_idade'].mode()

# Média (arredondada para o inteiro mais próximo)
media = round(dados_obito_doenca_cronica['nu_idade'].mean())

# Variância (arredondada para o inteiro mais próximo)
variancia = round(dados_obito_doenca_cronica['nu_idade'].var())

# Desvio padrão (arredondado para o inteiro mais próximo)
desvio_padrao = round(dados_obito_doenca_cronica['nu_idade'].std())

# Criando um DataFrame com os resultados
tabela_descricao = pd.DataFrame({
    'Estatística': ['Contagem', 'Média', 'Desvio Padrão', 'Mínimo', '25%(percentil 25)', 'Mediana(percentil 50)', 'Moda', '75%(percentila 75)', 'Máximo', 'Variância'],
    'Valor': [descricao_estatistica['count'], media, desvio_padrao, descricao_estatistica['min'], descricao_estatistica['25%'], mediana, moda.iloc[0], descricao_estatistica['75%'], descricao_estatistica['max'], variancia]
})

# Convertendo o DataFrame para uma tabela Markdown
tabela_markdown = tabela_descricao.to_markdown(index=False)

# Exibindo a tabela Markdown
print(tabela_markdown)
| Estatística           |   Valor |
|:----------------------|--------:|
| Contagem              |   82303 |
| Média                 |      72 |
| Desvio Padrão         |      15 |
| Mínimo                |       0 |
| 25%(percentil 25)     |      63 |
| Mediana(percentil 50) |      73 |
| Moda                  |      74 |
| 75%(percentila 75)    |      83 |
| Máximo                |     117 |
| Variância             |     231 |

Análise dos Resultados da Estatística Descritiva da Idade¶

  • Contagem: Temos um total de 82.303 observações de idade, o que nos indica o tamanho da amostra que estamos analisando.

  • Média: A idade média dos pacientes é de aproximadamente 72 anos. Isso sugere que a idade média dos pacientes que faleceram por essas doenças é relativamente alta.

  • Desvio Padrão: O desvio padrão de aproximadamente 15 anos indica que as idades dos pacientes variam consideravelmente em torno da média.

  • Mínimo e Máximo: O paciente mais jovem tinha 0 anos de idade, enquanto o mais velho tinha 117 anos. Isso mostra a ampla faixa de idades representadas nos óbitos por doenças crônicas não transmissíveis.

  • Percentis (25%, 50% e 75%): Estes fornecem informações sobre a distribuição das idades dos pacientes. Por exemplo, 25% dos pacientes tinham 63 anos ou menos (primeiro quartil), 50% tinham 73 anos ou menos (mediana) e 75% tinham 83 anos ou menos (terceiro quartil). Isso nos ajuda a entender onde a maioria das idades está concentrada na distribuição.

  • Moda: A idade mais comum entre os pacientes que faleceram por doenças crônicas não transmissíveis foi 74 anos. Comparando a moda com a média e a mediana, vemos que a moda está próxima da média, o que sugere que a distribuição das idades pode ser aproximadamente simétrica ou levemente assimétrica. Isso significa que há uma concentração significativa de pacientes em torno dessa idade.

  • Variância: A variância é uma medida de dispersão que indica o quão distantes os valores estão da média. Neste caso, uma variância de aproximadamente 231 indica que as idades dos pacientes tendem a variar em torno da média de idade (que é de aproximadamente 72 anos) em uma faixa de cerca de 231 anos.

Isso sugere que há uma dispersão considerável nas idades dos pacientes que faleceram por doenças crônicas não transmissíveis.


Essa análise estatística descritiva nos fornece uma compreensão abrangente das idades dos pacientes que faleceram por doenças crônicas não transmissíveis. Isso nos ajuda a entender a faixa etária desses pacientes, bem como a distribuição e a dispersão das idades em torno da média.


5.15. Gráfico da Análise de Óbito por Sexo¶

In [17]:
import seaborn as sns

# Reordenando os dados para garantir que a barra masculino apareça primeiro
dados_obito_doenca_cronica['sg_sexo'] = pd.Categorical(dados_obito_doenca_cronica['sg_sexo'], categories=['Masculino', 'Feminino'], ordered=True)

# Configurando o tamanho do gráfico
plt.figure(figsize=(10, 6))

# Usando o estilo "whitegrid"
sns.set_style("whitegrid")

print()

sns.countplot(x='sg_sexo', data=dados_obito_doenca_cronica, palette='pastel')
plt.title('Distribuição de Óbito por Sexo', fontsize=18, pad=20)   # pad define valor para espaçamento
plt.xlabel('Sexo', fontsize=14, labelpad=20)                             # eixo x
plt.ylabel('Número de Pacientes', fontsize=14, labelpad=20)              # eixo y

# Adicionando os valores no topo das barras
for index, value in enumerate(dados_obito_doenca_cronica['sg_sexo'].value_counts()):
    plt.text(index, value+1500, str(value), ha='center', va='top')

# Ajustando os limites do eixo Y para aumentar o espaço acima da barra mais alta
max_height = max(dados_obito_doenca_cronica['sg_sexo'].value_counts())
plt.ylim(0, max_height * 1.1)  # Aumenta o limite superior para criar mais espaço    
    
plt.show()
print()

No description has been provided for this image


5.16. Gráfico Apresenta os 10 Munícios com Maiores Números de Óbitos¶

In [18]:
# Gráfico para apresentar os 10 Municípios com Maiores Números de Óbitos


# Configurando o tamanho do gráfico
plt.figure(figsize=(12, 8))

# Limitando o número de municípios exibidos no gráfico para os top 10
top_municipios = dados_obito_doenca_cronica['co_municipio_ibge_residencia'].value_counts().nlargest(10)


# Definindo cores personalizadas
cores_personalizadas = ["blue", "green", "red", "purple", "orange"]

# Usando o estilo "whitegrid"
sns.set_style("whitegrid")

print()

# Plotando o gráfico de contagem com os 10 Municípios com Maiores Números de Óbitos
sns.barplot(x=top_municipios.index, y=top_municipios.values, palette=cores_personalizadas)
plt.title('Municípios com Maiores Números de Óbitos por Doença Crônica', fontsize=18, pad=20)
plt.xlabel('Município de Residência', fontsize=16, labelpad=20)
plt.ylabel('Número de Pacientes Falecidos', fontsize=16, labelpad=20)

# Definindo os rótulos do eixo x como os nomes dos municípios
plt.xticks(range(len(top_municipios.index)), top_municipios.index, rotation=45, ha='right', fontsize=14)

# Adicionando os valores no topo das barras
for index, value in enumerate(top_municipios.values):
    plt.text(index, value + 500, str(value), ha='center', va='top', fontsize=12)

# Ajustando os limites do eixo Y para aumentar o espaço acima da barra mais alta
max_height = max(dados_obito_doenca_cronica['co_municipio_ibge_residencia'].value_counts().values[:10])
plt.ylim(0, max_height * 1.15)  # Aumenta o limite superior para criar mais espaço
    
plt.tight_layout()
plt.show()
print()

No description has been provided for this image


5.17. Gráfico Apresenta as 2 Principais Doenças Crônica com Obito por Município¶

In [19]:
print()

# Configurando o tamanho do gráfico
plt.figure(figsize=(10, 8))

# Agrupando os dados por município e doença crônica, contando o número de óbitos para cada combinação
dados_agrupados = dados_obito_doenca_cronica.groupby(['co_municipio_ibge_residencia', 'categoria_cid_causa_basica']).size().reset_index(name='num_obitos')

# Para cada município, encontrar as 2 doenças crônicas com o maior número de óbitos
top_2_doencas_por_municipio = dados_agrupados.groupby('co_municipio_ibge_residencia').apply(lambda x: x.nlargest(2, 'num_obitos')).reset_index(drop=True)

# Ordenando os municípios pelas duas maiores doenças
ordenado_por_doencas = top_2_doencas_por_municipio.groupby('co_municipio_ibge_residencia').sum().nlargest(5, 'num_obitos').index

# Selecionando apenas os 5 principais municípios
top_5_municipios = top_2_doencas_por_municipio[top_2_doencas_por_municipio['co_municipio_ibge_residencia'].isin(ordenado_por_doencas)]

# Definindo uma paleta de cores com cores distintas para cada doença crônica
paleta = sns.color_palette("husl", len(top_5_municipios['categoria_cid_causa_basica'].unique()))

# Usando o estilo "whitegrid"
sns.set_style("whitegrid")

# Plotando o gráfico com as barras na vertical e usando a paleta personalizada
ax = sns.barplot(x='co_municipio_ibge_residencia', y='num_obitos', hue='categoria_cid_causa_basica', data=top_5_municipios, dodge=False, palette=paleta)

# ajustamos os limites do eixo y para aumentar o espaço acima da barra mais alta
max_height = max([p.get_height() for p in ax.patches])
ax.set_ylim(0, max_height * 1.2)  # valor para aumentar o limite superior para criar mais espaço

plt.title('Cinco Municípios com as Duas Maiores Doenças Crônicas', fontsize=18, pad=20)
plt.xlabel('Municípios', fontsize=16, labelpad=20)
plt.ylabel('Número de Óbitos', fontsize=16, labelpad=20)
plt.legend(title='Doença Crônica', title_fontsize='13', fontsize='11')

# Aumentando os valores de x (nome dos municípios) e y (números de óbitos)
plt.xticks(rotation=45, ha='right', fontsize=13)
plt.yticks(fontsize=13)

# Adicionando o número total de mortos no topo de cada barra com fonte Arial preta
for p in ax.patches:
    width = p.get_width()
    height = p.get_height()

    if height > 0:  # Verifica se o valor é válido
        
        # Calculando a coordenada y centralizada para cada faixa de cor
        y_coord = (height / 1.2)  # Calcula o topo da barra
        
        # Ajustando a posição do texto
        ax.annotate(f'{int(height)}', (p.get_x() + width / 2, y_coord), ha='center', fontsize=12, fontweight='normal', fontfamily='Arial', color='black', xytext=(2, 2), textcoords='offset points')

plt.tight_layout()
plt.show()

# Relatório Final
for index, row in top_5_municipios.iterrows():
    print(f"Município: {row['co_municipio_ibge_residencia']}, Doenças: {row['categoria_cid_causa_basica']}, Óbitos: {row['num_obitos']}")

No description has been provided for this image
Município: Belo Horizonte, Doenças: HIPERTENSAO ESSENCIAL, Óbitos: 741
Município: Belo Horizonte, Doenças: DIABETES MELLITUS NE, Óbitos: 532
Município: Contagem, Doenças: HIPERTENSAO ESSENCIAL, Óbitos: 187
Município: Contagem, Doenças: INFARTO AGUDO DO MIOCARDIO, Óbitos: 159
Município: Governador Valadares, Doenças: INFARTO AGUDO DO MIOCARDIO, Óbitos: 172
Município: Governador Valadares, Doenças: DIABETES MELLITUS NE, Óbitos: 114
Município: Juiz de Fora, Doenças: HIPERTENSAO ESSENCIAL, Óbitos: 234
Município: Juiz de Fora, Doenças: DIABETES MELLITUS NE, Óbitos: 168
Município: Uberaba, Doenças: INFARTO AGUDO DO MIOCARDIO, Óbitos: 153
Município: Uberaba, Doenças: OUTR DOENC PULMONARES OBSTRUTIVAS CRONICAS, Óbitos: 125

5.18. Análise de Correlação entre Variáveis no Contexto de Óbitos por Doenças Crônicas¶

In [20]:
import pandas as pd

# Seleciona apenas as colunas dos tipos desejados
dados_numericos = dados_obito_doenca_cronica.select_dtypes(include=['int32', 'datetime64[ns]'])

# Converte as datas para um formato numérico
dados_numericos['dt_obito_numerico'] = dados_numericos['dt_obito'].astype('int64')  # Converte a data do óbito para timestamp
dados_numericos['dt_nascimento_numerico'] = dados_numericos['dt_nascimento'].astype('int64')  # Converte a data de nascimento para timestamp

# Remove as colunas originais de datas
dados_numericos = dados_numericos.drop(columns=['dt_obito', 'dt_nascimento'])

# Calcula a matriz de correlação de Pearson
matriz_correlacao = dados_numericos.corr(method='pearson')

# Agora, matriz_correlacao contém os coeficientes de correlação de Pearson entre todas as variáveis numéricas
plt.figure(figsize=(12, 8))
sns.heatmap(matriz_correlacao, annot= True, cmap='coolwarm', fmt='.2f', annot_kws={"size": 10})
plt.title('Matriz de Correlação de Pearson', fontsize=18)
Out[20]:
Text(0.5, 1.0, 'Matriz de Correlação de Pearson')
No description has been provided for this image

Análise da Correlação:¶

  1. Correlação entre Idade e Data de Nascimento:

    • Alta correlação negativa (-1.00) entre a idade do paciente e sua data de nascimento, indicando que à medida que a idade aumenta, a data de nascimento recua no tempo, o que é esperado e confirma a integridade dos dados.

  1. Correlação entre Data do Óbito e Idade:

    • Correlação negativa muito baixa (-0.02) entre a data do óbito e a idade do paciente, indicando uma relação praticamente inexistente entre essas variáveis, sugerindo que a idade do paciente não está linearmente relacionada à data de óbito. Isso pode indicar que outros fatores, não apresentados nesses dados, além da idade, podem influenciar a mortalidade por doenças crônicas.

  1. Correlação entre Data do Óbito e Data de Nascimento:

    • Correlação positiva muito baixa (0.04) entre a data do óbito e a data de nascimento do paciente, sugerindo uma relação praticamente inexistente entre essas variáveis e que não estão linearmente relacionadas.

5.19. "Análise da Distribuição da Idade dos Pacientes Falecidos ao Longo do Tempo"¶

In [21]:
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib.ticker as mtick

# Reordenando os dados para garantir que a barra masculino apareça primeiro
dados_obito_doenca_cronica['sg_sexo'] = pd.Categorical(dados_obito_doenca_cronica['sg_sexo'], categories=['Masculino', 'Feminino'], ordered=True)


# Configurando o tamanho do gráfico
plt.figure(figsize=(10, 6))

# Usando o estilo "whitegrid"
#sns.set_style("whitegrid")

# Configurando o tamanho do gráfico
#plt.figure(figsize=(12, 8))

# Criando o gráfico de distribuição da idade ao longo do tempo
sns.histplot(data=dados_obito_doenca_cronica, x='nu_idade', hue='sg_sexo', kde=True, color='lightblue')

# Definindo os intervalos desejados no eixo x
plt.xticks(range(0, dados_obito_doenca_cronica['nu_idade'].max()+1, 10))

# Adicionando título e rótulos aos eixos
plt.title('Distribuição da Idade dos Pacientes Falecidos ao Longo do Tempo por Sexo', fontsize=18, pad=20)
plt.xlabel('Idade', fontsize=14, labelpad=20)
plt.ylabel('Número de Pacientes', fontsize=14, labelpad=20)

# Adicionando legenda manualmente
plt.legend(title='Sexo', loc='upper right', labels=['Masculino', 'Feminino'])

# Exibindo o gráfico
plt.show()
No description has been provided for this image