Исследовательский анализ данных по набору данных по болезням сердца UCI

Сердечно-сосудистые заболевания или болезни сердца являются основной причиной смерти среди женщин и мужчин и среди большинства расовых / этнических групп в Соединенных Штатах. Болезнь сердца описывает ряд состояний, которые влияют на ваше сердце. Заболевания, относящиеся к сердечно-сосудистым заболеваниям, включают заболевания кровеносных сосудов, такие как ишемическая болезнь сердца. По данным CDC, примерно каждая четвертая смерть ежегодно происходит из-за болезни сердца. ВОЗ утверждает, что основной причиной этой проблемы с сердцем является человеческий образ жизни. Помимо этого, существует множество ключевых факторов, которые предупреждают о том, что у человека может / не может быть шанса сердечного заболевания.

Мы будем использовать набор данных UCI о сердечных заболеваниях, найденный здесь, для проведения исследовательского анализа данных (EDA), во второй части мы построим классификационные модели и будем использовать методы ансамблирования для создания высокоточной модели. В текущем наборе данных публикации этого исследования включали 303 пациента и выбрали 14 из 76 характеристик, которые имеют значение для прогнозирования сердечных заболеваний.

Описание переменных

  1. age: возраст в годах
  2. пол: пол (1 = мужской; 0 = женский)
  3. cp: тип боли в груди - значение 1: типичная стенокардия, значение 2: атипичная стенокардия, значение 3: неангинальная боль, значение 4: бессимптомное течение
  4. trestbps: артериальное давление в состоянии покоя (в мм рт. ст. при поступлении в больницу)
  5. хол: холесторальный уровень сыворотки в мг / дл
  6. fbs: (уровень сахара в крови натощак ›120 мг / дл) (1 = верно; 0 = неверно)
  7. restecg: результаты электрокардиографии в покое - Значение 0: нормальное, Значение 1: наличие отклонения ST-T (инверсия зубца T и / или подъем или депрессия ST> 0,05 мВ), значение 2: указание Эстеса на вероятную или определенную гипертрофию левого желудочка критерии
  8. талах: достигнутая максимальная частота сердечных сокращений
  9. Пример: стенокардия, вызванная физической нагрузкой (1 = да; 0 = нет)
  10. oldpeak = депрессия ST, вызванная упражнениями по сравнению с отдыхом
  11. slope: наклон пикового сегмента ST при упражнении - Значение 1: восходящий, значение 2: ровный, значение 3: нисходящий
  12. ca: количество крупных сосудов (0–3), окрашенных флурозопией
  13. thal: 3 = нормальный; 6 = исправленный дефект; 7 = обратимый дефект
  14. цель: 1 = болезнь, 0 = нет болезни

Типы переменных

  1. Непрерывный - age, trestbps, chol, thalach, oldpeak
  2. Двоичный - sex, fbs, exang, target
  3. Категориальный - cp, restecg, slope, ca, thal

Давайте начнем с EDA!

Сначала мы импортируем необходимые библиотеки и читаем в нашем наборе данных.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.graph_objects as go # To Generate Graphs
import plotly.express as px # To Generate box plot for statistical representation
%matplotlib inline
import plotly.express as px
df=pd.read_csv('heart.csv')
df.head()

Описание переменных приведено выше, чтобы повторить, цель - это наша зависимая переменная, где 0 = нет болезней сердца и 1 = болезни сердца.

Давайте проверим, есть ли какие-либо значения данных ошибок, чтобы категориальные переменные имели правильное количество категорий, как описано выше. После проверки всех переменных мы обнаружили, что thal и ca имеют по одной дополнительной категории внутри каждой. Мы заменим эти значения на NaN, а затем заменим эти значения на медианные.

df.thal.value_counts()
#3 = normal; 6 = fixed defect; 7 = reversable defect
# OUTPUT
2    166
3    117
1     18
0      2
Name: thal, dtype: int64
# Replace 0 with NaN
df.loc[df['thal']==0, 'thal'] = np.NaN
df.ca.value_counts()
# number of major vessels (0-3) colored by flourosopy
# OUTPUT
0    175
1     65
2     38
3     20
4      5
Name: ca, dtype: int64
# Replace 4 with NaN
df.loc[df['ca']==4, 'ca'] = np.NaN
# Replace NaN with median values
df=df.fillna(df.median())

Затем давайте проверим выбросы, визуализировав коробчатую диаграмму

Из этой визуализации мы видим, что chol имеет экстремальное значение, которое мы заменим его средним значением.

Теперь мы создадим еще несколько визуализаций, чтобы лучше понять данные, используя plotly. Сначала давайте посмотрим на распределение нашей целевой переменной:

y=df.target.value_counts()
x=['Disease','No Disease']
fig=go.Figure(
    data=[go.Bar(x=x,y=y,text=y, textposition='auto',)],
                    layout=go.Layout(title=go.layout.Title(text='Target Variable (Heart Disease) Distribution')))
fig.update_xaxes(title_text='Target')
fig.update_yaxes(title_text='Number of Individuals')
fig.show()

Имеется небольшой дисбаланс классов, но он недостаточно серьезный, чтобы требовать применения методов повышения / понижения дискретизации.

Давайте посмотрим на распределение возраста в нашем наборе данных:

fig = px.histogram(df, x='age',color_discrete_sequence=['coral'])
fig.update_xaxes(title_text='Age')
fig.update_yaxes(title_text='Count')
fig.update_layout(title_text='Distribution of Age')
fig.show()

Из приведенного выше графика мы видим, что возраст большинства пациентов в текущем наборе данных составляет от 50 до 60 лет.

Давайте посмотрим на распределение пола по нашей целевой переменной:

female=df.loc[df['sex']==0]
female_values=female.target.value_counts()
male=df.loc[df['sex']==1]
male_values=male.target.value_counts()
target=['No Disease','Disease']
fig = go.Figure(data=[
    go.Bar(name='female', x=female_values.index, y=female_values, text=female_values, textposition='auto'),
    go.Bar(name='male', x=male_values.index, y=male_values, text=male_values, textposition='auto'),
])
fig.update_xaxes(title_text='Target')
fig.update_yaxes(title_text='Count')
fig.update_layout(title_text='Distribution of Sex According to Target Variable')
fig.update_layout(barmode='group')
fig.show()

Из приведенного выше графика видно, что в группе с сердечными заболеваниями (1) пациентов мужского пола больше, чем пациентов женского пола.

Затем давайте посмотрим, как различается боль в груди или стенокардия (cps) в нашей целевой переменной. Стенокардия возникает, когда сердечные мышцы не получают достаточно богатой кислородом крови, вызывая сильный дискомфорт в груди, часто также распространяющийся на плечи, руки и шею.

cp=['Typical Angina','Atypical Angina','Non-Anginal Pain','Asymptomatic']
y1=df.loc[df['target']==0].cp.value_counts()
y2=df.loc[df['target']==1].cp.value_counts()
fig = go.Figure(data=[
    go.Bar(name='Disease', x=cp, y=y2),
    go.Bar(name='No Disease', x=cp, y=y1)
])
fig.update_layout(barmode='group')
fig.update_xaxes(title_text='Chest Pain Type')
fig.update_yaxes(title_text='Count')
fig.update_layout(title_text='Distribution of Target Variable According to Chest Pain Type')
fig.show()

Из приведенного выше графика видно, что большинство здоровых пациентов испытывают типичную стенокардию, которая описывается как стеснение в груди по сравнению с больными пациентами. Кажется, также существует баланс между больными пациентами, которые испытали атипичную стенокардию и неангинальную боль.

Теперь давайте посмотрим, как изменяется уровень сахара в крови натощак (fbs) для переменной target. Fbs - индикатор диабета, при этом fbs ›120 мг / сут считается диабетическим (True):

dis=df.loc[df['target']==1]
dis_values=dis.fbs.value_counts()
nodis=df.loc[df['target']==0]
nodis_values=nodis.fbs.value_counts()
target=['No Disease','Disease']
d=['False','True']
fig = go.Figure(data=[
    go.Bar(name='Disease', x=d, y=dis_values, text=dis_values, textposition='auto'),
    go.Bar(name='No Disease', x=d, y=nodis_values, text=nodis_values, textposition='auto'),
])
fig.update_layout(barmode='group')
fig.update_xaxes(title_text='Fasting Blood Sugar (fbs)')
fig.update_yaxes(title_text='Count')
fig.update_layout(title_text='Distribution of Target Variable According to Fasting Blood Sugar')
fig.show()

Здесь мы видим, что число для класса true ниже, чем для класса false. Это указывает на то, что fbs не может быть сильным признаком, позволяющим отличить сердечное заболевание от здорового пациента.

Резюме

В этой статье мы продемонстрировали некоторые методы EDA, которые могут быть применены к набору данных UCI по сердечным заболеваниям при подготовке к построению классификационной модели. Мы также создали несколько визуализаций, чтобы лучше понять данные и определить, какие переменные могут влиять на различие между больными и здоровыми пациентами. Во второй части я буду строить классификационную модель и использовать ансамблевые методы для создания более точной модели.

Спасибо, что прочитали :) Весь код размещен на моем Github.