Итак, я наткнулся на набор данных, содержащий несколько медицинских записей, связанных с сердечными заболеваниями, в репозитории машинного обучения UCI. Что меня заинтересовало, так это реальное значение, которое это может принести медицинскому миру. Конечно, модель, которую я пытаюсь построить здесь, далека от «достаточно», она слишком упрощена. Цель этой статьи не в том, чтобы научить вас сложным методам машинного обучения, но я хочу, чтобы вы немного узнали, как на самом деле работает машинное обучение. Я не буду тратить больше вашего времени, так что давайте начнем путешествие!

Наконец, что не менее важно, может быть включен некоторый академический жаргон, потому что, да, здоровье и наука о данных действительно являются довольно серьезными предметами. Не волнуйтесь, я постараюсь сделать это как можно более приятным для чтения ❤

К вашему сведению, доступ к набору данных можно получить здесь

Введение в дело

Сердечно-сосудистые заболевания (ССЗ), широко известные в Индонезии как «пеньякит джантунг», являются основной причиной смерти в мире, унося примерно 17,9 миллиона жизней ежегодно, или 31% глобальной смертности. Только в Индонезии сердечно-сосудистые заболевания являются причиной 37% смертей. Основной причиной становится инсульт, за которым следуют ишемическая болезнь сердца и диабет.

Большинство сердечно-сосудистых заболеваний на самом деле поддаются лечению, и мы можем управлять поведенческими факторами риска (например, курением, диетой, ожирением, физической активностью, употреблением алкоголя и т. д.), чтобы снизить вероятность ранней смерти от сердечно-сосудистых заболеваний.

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

Цель сегодняшнего исследования — создать модель, которая может успешно предсказать положительный случай (1) с вероятностью выше, чем случайное угадывание (0,5). Мы делаем это, имея оценку отзыва выше 0,5 для положительного случая. Какова оценка отзыва, спросите вы? Что ж, правда откроется, когда мы отправимся в путь ^^

Итак, прежде чем мы начнем, давайте импортируем все наши инструменты и наш набор данных! (P.S: я буду писать код Python3 только для модели с SMOTE)

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
df = pd.read_csv('heart_failure_clinical_records_dataset.csv')
df.head()

Описание данных

Откуда взялись данные? исходные данные были собраны Танвиром и его другом в июле 2017 года. Текущая версия, которую мы используем для анализа, является более новой версией, предоставленной Давиде Чикко (Исследовательский институт Крембиля, Торонто, Канада) в январе 2020 года. .

Сердечная недостаточность является распространенным симптомом, вызванным сердечно-сосудистыми заболеваниями, и этот набор данных содержит 12 переменных (и мы будем называть их признаками, потому что это сексуальнее), которые можно использовать для прогнозирования интересующей нас переменной. больше всего (ярлык). Ну, на самом деле есть одна переменная, которую мы не будем использовать для этого анализа, и это время. Причина будет ясна по мере нашего продвижения. Итак, мы будем использовать 11 функций, которые состоят из медицинских данных пациентов, таких как их возраст, наличие у них анемии, наличие у них диабета и многие другие медицинские термины. Не беспокойтесь, вы можете прочитать остальное в более простом для понимания виде:

  • age: возраст пациента (в годах)
  • анемия: есть ли снижение эритроцитов или гемоглобина (0: нет, 1: да)
  • высокое кровяное давление: если у пациента гипертония (0: нет, 1: да)
  • креатининфосфокиназа (КФК): уровень фермента КФК в крови (мкг/л)
  • диабет: если у пациента диабет (0: нет, 1: да)
  • фракция выброса: процент крови, покидающей сердце при каждом сокращении (в процентах)
  • тромбоциты: тромбоциты в крови (килотромбоциты/мл)
  • пол: женщина или мужчина (0: женщина, 1: мужчина)
  • креатинин сыворотки: уровень креатинина сыворотки в крови (мг/дл)
  • сывороточный натрий: уровень сывороточного натрия в крови (мэкв/л)
  • курение: курит пациент или нет (0: нет, 1: да)
  • время: период наблюдения (дни)
  • событие смерти: если пациент умер в течение периода наблюдения (0: не смерть, 1: смерть). Это наша цель. Который нас интересует больше всего.

Видите ли, переменная время — это период наблюдения за пациентом. Они собрали время после того, как также было собрано событие смерти. Таким образом, мы не можем использовать время для прогнозирования события смерти, потому что мы не можем получить доступ к этой переменной, если также не доступно событие смерти нам. Если нам доступно событие смерти, то не нужно ничего предсказывать и мы можем продолжать играть с нашими котиками ^^

Прежде чем мы продолжим, нам нужно проверить, есть ли в наших данных некоторые пропущенные значения.

df.isnull().sum()

Что ж, к счастью, как видите, в наших данных нет пропущенных значений, так что все готово!

Разделение данных и стандартизация

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

x = df.iloc[:,0:11].values
y = df['DEATH_EVENT'].values
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test= train_test_split(x, y, test_size= 0.3,
random_state=0)

Прежде чем мы начнем использовать данные для модели классификации, нам необходимо стандартизировать все числовые переменные. Почему? потому что эти переменные измеряют разные вещи (например, возраст измеряется в годах, креатининфосфокиназа измеряется в мкг/л, количество тромбоцитов измеряется в килотромбоцитах/мл и т. д.), и при их стандартизации все переменные могут вносить одинаковый вклад и мы можем избежать предвзятости в модели.

Например, переменная, которая находится в диапазоне от 0 до 1000, определенно перевесит переменную, которая находится в диапазоне от 0 до 1. Использование этих переменных без стандартизации даст переменной с большим диапазоном (от 0 до 1000) более высокий вес в анализе. Преобразование данных в сопоставимые масштабы может предотвратить такую ​​проблему.

Метод стандартизации, который мы будем использовать сегодня, заключается в удалении среднего значения (обозначается полосой x, той, что с линией на голове) и масштабировании до единичной дисперсии (обозначается s).

from sklearn.preprocessing import StandardScaler
st_x= StandardScaler()
x_train= st_x.fit_transform(x_train)
x_test= st_x.transform(x_test)

Бинарный метод классификации

В этом конкретном крошечном отрезке времени во Вселенной мы будем использовать KNN (K-ближайший сосед) в качестве нашего метода классификации. KNN – это контролируемый метод машинного обучения, которому нужны помеченные данные для обучения модели, чтобы она могла классифицировать новые немаркированные функции (это все равно, что угадывать результат подбрасывания монеты до того, как он земли, за исключением того, что это не предположение, а расчет), основанный на расчетах.

Но почему он называется «Ближайший сосед»? Что такое классификационная модель? Проще говоря, классификационная модель на самом деле просто делает то, что описывает ее название, классифицируя объекты по 2 или более категориям, точно так же, как ученые классифицируют животных по видам (ярлык) на основе их характеристик (их функции). Но то, что мы делаем прямо сейчас, — это бинарная классификация, что означает, что возможная метка — всего 2. Мы только категоризируем/классифицируем людей по 2 группам, вместо того, чтобы ученые классифицировали животных по списку видов (пссс… на самом деле их 8,7). миллионов видов в мире). Ну, люди говорили, что картинка может описать тысячу слов.

На картинке видно, что цвет соответствует ярлыку. Точки, находящиеся в области определенного цвета, относят к одной группе. Прямо сейчас вы, должно быть, знаете, почему это называется «k ближайший сосед», верно? Это связано с тем, что модель пытается классифицировать конкретную точку данных (представленную точками) в ту или иную группу на основе других ближайших к ним точек данных. Как говорится в старой поговорке «Рыбак рыбака слетается в стаю», вещи, которые имеют схожие характеристики, часто принадлежат к одной и той же группе. Машинное обучение действительно восприняло это более буквально ^^. Но что такое K в KNN? в основном это решить, сколько «других ближайших точек данных» мы хотим увидеть, прежде чем решить, к какой группе принадлежит эта точка данных.

Метод передискретизации

Как видно из предыдущего раздела, при изучении данных мы обнаружили, что доля ярлыка даже близко не равна. Если оставить все как есть, то модель, скорее всего, будет иметь смещение. Почему?

Допустим, моя любимая кошка Мико предпочитает есть влажный корм 99 раз из 100 попыток. Если затем я создам модель, чтобы предсказать, будет ли Мико есть влажный корм или сухой корм, модель может просто сказать, что это будет влажный корм. > и всегда будет прав в 99% случаев без всяких расчетов. Вот почему у нас должен быть пропорциональный случай каждого решения, которое выбрала Мико, чтобы модель действительно использовала некоторые функции, влияющие на решение Мико.

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

from imblearn.over_sampling import SMOTE
sm = SMOTE(random_state = 0)
x_train_smote, y_train_smote = sm.fit_resample(x_train, y_train)
sns.countplot(x = y_train_smote)

Видеть? теперь количество случаев, когда death_event = 1, совпадает с количеством случаев, когда death_event = 0. Затем давайте перейдем к главному прожектору, создав классификацию модель.

Полученные результаты

Итак, вот часть, которая должна быть веселой!

Сначала нам нужно импортировать наши инструменты. В Python большинство людей начинают использовать машинное обучение через Scikit Learn, поэтому давайте воспользуемся ими. Помните, что поскольку у нас есть дисбаланс классов (у нас гораздо больше 0, чем 1 в DEATH_EVENT, который является нашей меткой), мы будем использовать 2 модели и сравнивать их производительность. Вы можете сравнивать моделей, но, пожалуйста, не сравнивайте себя с другими, каждая по-своему красива ❤

Первый способ действий — найти лучшее «k», под лучшим мы подразумеваем тот, который имеет наименьшую частоту ошибок. Мы можем сделать это, просто зациклившись.

error = []
for i in range(1, 30):
 knn = KNeighborsClassifier(n_neighbors=i)
 knn.fit(x_train_smote, y_train_smote)
 pred_i = knn.predict(x_test)
 error.append(np.mean(pred_i != y_test))
plt.figure(figsize=(12, 6))
plt.plot(range(1, 30), error, color='red', linestyle='dashed', marker='o',
 markerfacecolor='blue', markersize=10)
plt.title('Error Rate K Value')
plt.xlabel('K Value')
plt.ylabel('Mean Error')
print("Minimum error:-",min(error),"at K =",error.index(min(error))+1)

Мы видим, что две модели, которые мы используем (без SMOTE и со SMOTE), имеют разные «лучшие K», но это совсем не проблема, потому что вам не нужно использовать одно и то же число k для обеих моделей. Для модели без SMOTE лучший K равен 4, а для модели со SMOTE лучший K равен 24. Теперь давайте попробуем обучить нашу модель.

classifier= KNeighborsClassifier(n_neighbors=24)
classifier.fit(x_train_smote, y_train_smote)
y_pred= classifier.predict(x_test)

Матрица путаницы

Итак, мы попробовали запустить алгоритм KNN для обеих моделей, и что дальше? тявкать! теперь нам нужно оценить, какая модель работает лучше всего, опять же, в этом контексте значение зверя имеет наименьшую ошибку. Но как мы можем измерить ошибки?

Добро пожаловать в не очень запутанную матрицу путаницы! Матрица путаницы строится точно так же, как таблица непредвиденных обстоятельств.

  • Истинно положительный = означает, сколько данных на самом деле являются положительными (1) и что модель успешно предсказывает как положительные (1).
  • True Negative = означает, сколько данных на самом деле являются отрицательными (0) и что модель успешно спрогнозировала как отрицательные (0).
  • Ложноотрицательный = означает, сколько данных на самом деле являются положительными (1), НО модель неправильно предсказала отрицательные (0).
  • Ложноположительный = означает, сколько данных на самом деле отрицательные (0), НО модель неправильно предсказала как положительную (1).

Легко, верно? хорошо, давайте попробуем увидеть матрицу путаницы обеих наших моделей.

from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_test, y_pred)
fig, ax = plt.subplots(figsize=(5, 5))
ax.matshow(cm, cmap=plt.cm.Oranges, alpha=0.3)
for i in range(cm.shape[0]):
     for j in range(cm.shape[1]):
 ax.text(x=j, y=i,s=cm[i, j], va='center', ha='center', size='xxlarge')
plt.xlabel('Predictions', fontsize=18)
plt.ylabel('Actuals', fontsize=18)
plt.title('Confusion Matrix', fontsize=18)
plt.show()

Вы видите это? матрица путаницы в модели без SMOTE имеет гораздо больше ИСТИННО-ПОЗИТИВНЫХ, но гораздо меньше ИСТИННО-ОТРИЦАТЕЛЬНЫХ. Это происходит из-за несбалансированного класса label, который затем обрабатывается моделью классификации, использующей SMOTE.

Отчет о классификации

Что теперь? хорошо, матрица путаницы дала нам общее представление о производительности модели, но разве нам не нужно лучшее, одно суммированное число, чтобы представить их производительность? например, как люди измеряют общую академическую успеваемость учащихся по их среднему баллу? Ну, у нас также есть такие в Машинном обучении ^^ Это:

  • Точность = общее количество правильных прогнозов модели.

  • Точность = Когда модель предсказала положительный случай, сколько из этих случаев оказались правильными?

  • Отзыв (Чувствительность) = Когда фактический случай положительный, сколько из этих случаев правильно предсказано моделью?

  • F1-Score = Гармоническое среднее значение Precision and Recall.

Почему у нас должны быть все эти разные измерения? почему бы нам просто не выбрать один? ну, все они важны, но нам может не понадобиться использовать их все сразу.

Целью нашей модели было предсказать, умрет ли кто-то из-за болезни сердца или нет. Поэтому на самом деле важно успешно прогнозировать положительные случаи (1) по сравнению с фактическими положительными случаями. Когда нам не удалось предсказать положительный случай, результат может вызывать беспокойство. Эти люди нуждаются в уходе. Таким образом, цена неправильного предсказания положительного случая высока. Итак, если мы вернемся к приведенному выше уравнению, нас действительно заинтересует показатель отзыва положительного случая (1) этой модели.

from sklearn.metrics import classification_report
print(classification_report(y_test, y_pred))

Теперь мы видим, что оценка отзыва положительного случая (1) в модели без SMOTE составляет 0,14, что очень мало, в то время как у модели с SMOTE гораздо более высокая оценка отзыва. что 0,64! Это увеличение на 0,5 балла! ура!

Сводка

Как и в каждом путешествии, у каждого начала есть конец. Мы, наконец, подошли к концу нашего путешествия, и пришло время обобщить все, что мы узнали. Основываясь на модели классификации, которую я создал с помощью K-ближайших соседей (KNN), мы узнали несколько важных вещей:

  • Мы успешно достигли цели, которую мы поставили в начале, а именно иметь положительную оценку отзыва более 0,5 (мы получили 0,64).
  • Важность использования метода передискретизации, если у нас есть несбалансированный класс label. Некоторые из методов, которые мы можем использовать, это SMOTE или SMOTEEN.
  • Мы можем измерить производительность модели классификации с помощью ее отчета о классификации (точность, точность, полнота и оценка f1). Мы видим, что использование KNN со SMOTE оказывает большое влияние, как видно из увеличения на 0,5 балла нашей оценки отзыва.
  • В следующий раз было бы очень здорово, если бы мы использовали разные методы классификации (например, SVM, логистическую регрессию, наивную байесовскую модель, дерево решений, искусственную нейронную сеть и т. д.), чтобы сравнить их производительность и выбрать модель с лучшими показателями. . То же самое касается использования SMOTE и SMOTEEN для последующего сравнения результатов.

Ссылка

Chicco D, Jurman G. 2020. Машинное обучение может прогнозировать выживаемость пациентов с сердечной недостаточностью только по креатинину сыворотки и фракции выброса. BMC Медицинская информатика и принятие решений.

Jian C, Gao J, Ao Y. 2016. Новый метод выборки для классификации несбалансированных данных на основе ансамбля опорных векторов. Нейрокомпьютинг. 193(6): 115–122.

Сангуанмак Ю., Ханскунатай А. 2016. Автонастройка параметров гибридного метода выборки для решения проблемы дисбаланса классов. 2016 Международная конференция по информатике и инженерии (ICSEC). Чиангмай, Таиланд: IEEE.

Сапутро И.В., Сари Б.В. 2019. Uji Performa Algoritma Naïve Bayes untuk Prediksi Masa Studi Mahasiswa. Журнал творческих информационных технологий. 6(1): 1–11.

Шен Л., Линь З., Хуанг К. 2016. Ретрансляционное обратное распространение для эффективного обучения глубоких сверточных нейронных сетей. Европейская конференция по компьютерному зрению (ECCV 2016) (Hal. 467–482). Чам: Спрингер.

Джордж Институт глобального здравоохранения. 2017. Снижение бремени сердечно-сосудистых заболеваний в Индонезии. [Диаксес 2021 Дез 19]. www.georgeinstitute.org.au.

Wibowo F, Hakim DK, Sugiyanto S. 2018. PENDUGAAN KELAS MUTU BUAH PEPAYA BERDASARKAN CIRI TEKSTUR GLCM MENGGUNAKAN ALGORITMA K-БЛИЖАЙШИЕ СОСЕДИ. Jurnal National Pendidikan Teknik Informatika. 7(1): 100–107.

Чжан З. 2016. Введение в машинное обучение: k-ближайшие соседи. Hemodial Int J Transl Med.