Análise Epidemiológica de Óbitos: Explorando Padrões e Tendências para Informar Políticas de Saúde Pública
1. Descrição Geral do Problema¶
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).
# 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¶
# 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¶
dados_obito_doenca_cronica.head()
| 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¶
# 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¶
# 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
| 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¶
# 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.
#*************************************************************************************************
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¶
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¶
dados_cid.head()
| 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.
# 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¶
# 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¶
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¶
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
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¶
#******************************************************************************
# 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()
5.14. Estatística Descritiva da Idade¶
# 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¶
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()
5.16. Gráfico Apresenta os 10 Munícios com Maiores Números de Óbitos¶
# 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()
5.17. Gráfico Apresenta as 2 Principais Doenças Crônica com Obito por Município¶
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']}")
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¶
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)
Text(0.5, 1.0, 'Matriz de Correlação de Pearson')
Análise da Correlação:¶
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.
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.
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"¶
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()