Болезни сердца в настоящее время являются основной причиной смерти в Соединенных Штатах[1]. В дополнение к разрушительным потерям и эмоциональной боли, вызванной болезнью сердца, это также большое финансовое бремя. По оценкам, случаи сердечных заболеваний составляют большую часть ежегодных прямых расходов на здравоохранение в размере более 320 миллиардов долларов США [2]. Чтобы сократить ошеломляющее количество потерянных жизней и финансовое бремя этого заболевания, было бы чрезвычайно полезно иметь возможность предсказывать, разовьется ли у человека болезнь сердца и в какой степени. Текущие прогностические модели используют несколько ключевых факторов, таких как артериальное давление, общий холестерин и холестерин ЛПНП, для прогнозирования заболеваемости сердечными заболеваниями [3], однако эти модели не могут предсказать тяжесть сердечных заболеваний. Более точные прогнозы развития сердечных заболеваний и их тяжести будут иметь огромные социальные и экономические преимущества, и поэтому в этом проекте я стремился построить модель, которая может предсказывать сердечные заболевания и тяжесть сердечных заболеваний. Благодаря огромным социальным и экономическим преимуществам такой модели может быть много заинтересованных сторон. Для целей этого проекта я предполагал, что клиентом будет страховая компания. В этом отчете я подытожу технические детали создания классификатора для прогнозирования сердечно-сосудистых заболеваний и их тяжести, в том числе то, как я очищал / обрабатывал данные и как я пришел к выводу об использовании алгоритма классификации случайного леса. В заключение я резюмирую выводы этой работы и даю рекомендации клиенту. Наконец, я обращаюсь к ограничениям этой работы.

Для начала я получил доступ к данным через репозиторий UCI. Было 3 набора данных, каждый из которых содержал данные о пациентах из 3 уникальных больниц. Каждый набор данных содержал около 200 уникальных строк данных и те же 76 атрибутов. Первым шагом была загрузка каждого набора данных во фрейм данных pandas в соответствующем формате и устранение очевидных бессмысленных функций. Большинство из 76 признаков нельзя было использовать для разработки прогностической модели. Некоторые функции содержали имя пациента, номер социального страхования или идентификационный номер пациента. Другие столбцы функций были полностью пустыми, а другие столбцы функций были помечены как «Не использовать», «Нерелевантно», «Не уверен, что данные были собраны последовательно» или «Не уверен в единицах». Я выбросил все такие столбцы функций. Кроме того, у некоторых функций не было объяснения, что это за функция. В этих случаях столбцы признаков обозначались серией букв или цифр без каких-либо указаний на то, какой тип данных содержит столбец признаков. Я также выбросил их, потому что было бы бесполезно говорить клиенту: «Вот некоторые неизвестные функции, которые могут предсказать болезнь сердца». После обработки и очистки первоначальных данных у меня осталось 20 оставшихся функций. Характеристики представляли собой смесь категориальных переменных и непрерывных переменных.

Изучив данные, я обнаружил, что большинство столбцов функций содержат довольно много отсутствующих значений (обозначенных -9) и несколько значений, равных 0. Добавление некоторого «джиттера» к графикам было полезно при изучении категориальных данных. Добавленный джиттер помогает уменьшить разброс данных, а не использовать традиционный график, на котором данные всех участников перекрываются в случае категориальных переменных.

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

Я попробовал несколько разных методов работы с пропущенными значениями:

Вариант 1 — обычные данные) Я использовал все данные, включая -9 и 0. Я не принимал никаких решений по вменению данных или выбору признаков, а просто хотел посмотреть, как отрицательные значения и нулевые значения влияют на модели. Иногда недостающие данные могут быть информативными. Например, может случиться так, что люди, для которых не существует максимальной меры частоты сердечных сокращений, не смогли пройти кардиологический стресс-тест из-за других проблем со здоровьем, которые могут иметь отношение к прогнозированию сердечных заболеваний. Однако, насколько я знаю, данные отсутствуют случайным образом.

Вариант 2 — OneHotEncoder) Во-первых, я установил порог данных таким образом, что если функция содержала более 50% отсутствующих значений, я полностью удалил эту функцию. Некоторые источники предполагают, что если отсутствует более 50% данных, то вменение такого большого количества недостающих данных не добавит прочности модели [4]. Затем я использовал метод OneHotEncoder для кодирования категориальных переменных. Это устраняет числовой порядок категориальных переменных (1,2,3,4), который может обмануть модель, заставив ее думать, что порядок имеет смысл. Для непрерывных данных я проверил, существуют ли какие-либо отношения между функциями, которые могли бы указать способ вменения отсутствующих значений. Например, если бы частота сердечных сокращений в покое и максимальная частота сердечных сокращений были линейно связаны, то я мог бы использовать линейную модель для расчета отсутствующих значений частоты сердечных сокращений в состоянии покоя на основе максимальных значений частоты сердечных сокращений. Кроме того, если две функции сильно коррелированы, то одна функция может быть исключена, поскольку мультиколлинеарность может повлиять на прогностическую способность некоторых моделей. Например, деревья решений выбирают одну функцию, чтобы максимизировать получение информации, и поэтому страдают, когда две функции сильно коррелируют. В этом случае я обнаружил, что никакие две функции не были сильно коррелированы. Поэтому я вменил недостающие значения непрерывным функциям со средним значением каждой функции.

Вариант 3 — Label Coded) Я установил порог данных так же, как и выше. Если отсутствовало более 50% значений функции, этот столбец удалялся. Все непрерывные признаки вводились так же, как и в варианте 2 (со средним значением). Для категориальных переменных было сохранено исходное кодирование меток (0,1,2,3,4). Отсутствующие значения в категориальных признаках были вменены с использованием режима каждого категориального признака.

Вариант 4 — Нормализованные данные) Данные были обведены порогом и импутированы, как описано в варианте 3. Все непрерывные данные были нормализованы. Некоторым классификаторам, таким как машина опорных векторов, требуются нормализованные данные для более точных прогнозов.

Затем я выбрал несколько классификаторов для обучения и выбрал метрики оценки. Каждый из четырех наборов данных был разделен на обучающие данные и тестовые данные, а обучающие данные впоследствии использовались для обучения каждого классификатора и сравнения показателей оценки. Это контролируемый набор данных обучения, поскольку метки результатов даны. Я выбрал следующие методы обучения с учителем: логистическая регрессия, knn, дерево решений, случайный лес и метод опорных векторов. Для оценки я решил рассмотреть различные показатели. Точность оценки обучающих данных является важной мерой, поскольку она показывает, насколько хорошо каждая модель предсказывает обучающие данные. Я также вычислил оценку перекрестной проверки (среднее значение в 5 раз) для каждого классификатора. Цель перекрестной проверки состоит в том, чтобы выбрать разные разделы обучающих данных и протестировать классификатор на каждом разделе, чтобы классификатор не был смещен только к одному разделу. Перекрестная проверка помогает при переоснащении.

Я также рассмотрел точность, полноту и площадь под ROC-кривой для каждого классификатора. Площадь под ROC-кривой является широко используемой метрикой в ​​задачах бинарного класса. В случае этой многоклассовой задачи парадигма «один v остаток» использовалась для создания 5 бинарных задач (класс 0 против всех остальных классов, класс 1 против всех остальных классов и т. д.), и была рассчитана площадь под 5 результирующими ROC-кривыми. Мы хотим максимизировать площадь под кривой ROC, что происходит с максимальным количеством истинных срабатываний и минимальным количеством ложных срабатываний (см. пример модели из scikit Learn ниже).

В задаче с несколькими классами, такой как эта, в которой мы создаем 5 бинарных классификаторов, площадь под кривой может быть не лучшей метрикой для использования, поскольку она может дать нам очень высокие и потенциально вводящие в заблуждение области под кривой. Например, в случае классификатора класса 4 против остальных площадь под ROC-кривой очень высока (около 0,9), потому что сотни образцов, которые были точно классифицированы как не принадлежащие к классу 4, были классифицированы как истинно положительные, даже в случай неправильной маркировки в остальной группе (например, если экземпляр класса 3 был классифицирован как класс 2). Поэтому в дополнение к площади под кривой ROC я также рассмотрел такие показатели, как точность, полнота и показатель F1 (гармоническое среднее точности и полноты), которые особенно полезны в случаях дисбаланса классов. В этом случае набор данных несбалансирован — класс 0 (отсутствие болезни сердца) составляет 40% набора данных, тогда как класс 4 (самая тяжелая форма болезни сердца) составляет только 4% набора данных (см. ниже).

Одно ключевое различие между расчетом площади под кривой ROC (где TP = TP/TP + FN и FP = FP/FP + TN) и оценкой F1 (где точность = TP/TP + FP и полнота = TP/TP + FN), заключается в том, что расчет площади включает истинные отрицательные значения, а показатель F1 — нет. Следовательно, расчет площади с большей вероятностью будет искажен из-за несбалансированных наборов данных, чем оценка F1, как описано выше (у нас есть много TN, как с классификатором класса 4 v rest, который потенциально может исказить площадь под метрикой кривой ROC).

Я попробовал каждый из 5 классификаторов (логистический, knn, дерево решений, случайный лес и svm) с каждым из 4 вариантов очищенных наборов данных. В конечном счете, все варианты наборов данных дали одинаковые оценки, однако я обнаружил, что точность и полнота были постоянно выше для модели случайного леса с набором данных 2 — OneHotEncoder. Ниже приводится краткое описание категориальных и непрерывных признаков в наборе данных 2.

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

Первым классификатором, который я попробовал, была логистическая регрессия. Логистическая регрессия не может решить проблему мультикласса «из коробки». Мне пришлось бинаризировать данные, используя систему One v. Rest. В данном случае для обучения мультиклассового логистического классификатора было обучено 5 уникальных классификаторов. На этом раннем этапе был выбран стандартный штраф L2 вместе с решателем lbfgs, способным обрабатывать многоклассовые наборы данных. В каждом из четырех наборов данных логистическая регрессия имела низкую оценку точности и оценку перекрестной проверки (около 50%), что свидетельствует о высокой систематической ошибке.

Затем я попробовал модель дерева решений. Сначала я думал, что это будет самая идеальная модель из-за простоты обработки как категориальных, так и непрерывных переменных, а также ее легкой интерпретируемости. Однако я обнаружил, что модель дерева решений имеет высокую дисперсию и, таким образом, переобучает данные, о чем свидетельствует высокая оценка точности (~ 0,99), но низкая оценка cross_val (~ 0,48).

Случайные леса могут помочь в борьбе с переоснащением, наблюдаемым в деревьях решений, поскольку они вводят 2 источника рандомизации: 1) построение случайной начальной выборки с заменой из исходного набора данных, из которого можно вырастить дерево решений, и 2) построение случайной выборки функций без замены из исходного набора данных для каждого дерева решений. Я попробовал модель случайного леса на всех наборах данных и обнаружил, что хотя показатель cross_val был примерно таким же, как и для логистической регрессии (~ 0,48), показатели точности и полноты были постоянно выше для каждого класса при использовании случайного леса по сравнению с логистической регрессией. . В этом случае я хочу максимизировать показатели точности, чтобы максимизировать количество раз, когда мы точно предсказываем ярлык болезни сердца.

Я также попробовал k-ближайших соседей и модели опорных векторов. Оценка cross_val для этих моделей снова была одинаковой по сравнению со случайным лесом (~ 0,48). Однако в целом показатели точности и полноты для этих двух моделей были ниже по сравнению со случайным лесом.

Изучив все показатели оценки для всех классификаторов во всех 4 наборах данных, я выбрал модель случайного леса с набором данных 2 — OneHotEncoder. Однако важно отметить, что в этом случае ни один набор данных не оказался намного лучше, чем любой другой набор данных. Набор данных 2 имел некоторые небольшие преимущества по сравнению с другими наборами данных при использовании с моделью случайного леса (незначительно более высокие показатели cross_val и F1). Ниже приведен пример показателей оценки для модели «Случайный лес» (слева) и модели логистической регрессии (справа) для набора данных 2. Этот пример показывает, что, хотя показатели cross_val одинаковы для обеих моделей, показатели точности постоянно выше для каждого класса, когда используется модель случайного леса.

На этом этапе, после выбора модели случайного леса в наборе данных 2, OneHotEncoder, я стремился оптимизировать гиперпараметры случайного леса. В этой модели не так много гиперпараметров, о которых нужно беспокоиться, и нам не нужно так сильно беспокоиться о переобучении и, таким образом, указании оптимального количества узлов, как мы делаем с деревьями решений. Однако, чтобы предотвратить переоснащение, я выбрал набор чисел дерева решений (n_estimators). Этот набор данных небольшой, поэтому нам может не понадобиться столько деревьев, как для более крупного и сложного набора данных. Другими ключевыми гиперпараметрами, которые я выбрал для оптимизации, были максимальное количество функций и критерии получения информации (джини или энтропия). Джини и энтропия — это две меры прироста информации, а деревья решений/случайные леса работают, максимизируя прирост информации в каждом узле. Хотя расчеты Джини и энтропии различны, эти два показателя дают очень похожую информацию, и поэтому изменение критерия не должно сильно повлиять на точность модели.

После оптимизации гиперпараметров я протестировал оптимизированный случайный лес на тестовых данных или наборе данных удержания. Точность предсказания каждого класса в наборе тестовых данных оказалась высокой (> 90%), однако важно отметить, что точность не является лучшим показателем в случае несбалансированной задачи с несколькими классами. Чтобы оценить точность прогнозирования для каждого класса, мы должны бинаризировать данные по принципу «один против остальных». При этом мы часто получаем небольшой положительный класс и очень большой отрицательный класс (как в случае с классом 4, где 4 экземпляра в тестовом наборе принадлежат к классу 4, а 120 — нет). В этом случае точность прогноза действительно высока, даже несмотря на то, что модель не смогла точно предсказать НИ ОДИН из 4 положительных случаев. Это произошло потому, что модель была взвешена по всем отрицательным экземплярам. Предсказав, что все образцы относятся к отрицательному классу, мы достигли высокой точности предсказания для класса 4, потому что технически только 4 образца были классифицированы неправильно — 4 положительных случая, которые мы действительно хотим точно предсказать.

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

Для дальнейшего исследования того, сколько раз модель предсказывала истинные положительные и истинные отрицательные значения, я рассчитал матрицу путаницы. Опять же, здесь мы видим, что модель довольно хорошо предсказывает класс 0, но не другие классы.

Поэтому я делаю вывод, что модель хорошо работает для прогнозирования класса 0, но не для других классов. С этой целью я бинаризировал данные (отсутствие сердечных заболеваний = 0, сердечные заболевания = 1), чтобы исследовать ключевые особенности, которые могут предсказать возникновение сердечных заболеваний. Ниже представлено дерево решений результатов. Это дерево решений позволило мне прийти к следующим рекомендациям: Лица с бессимптомной болью в груди в возрасте до 54,5 лет, у которых нет плоского наклона пикового сегмента ST при физической нагрузке, НЕ склонны к развитию сердечных заболеваний (103 в классе 0). и 11 в 1 классе). У женщин с бессимптомной болью в груди, у которых пиковый сегмент ST не имеет наклона вверх, а также у женщин, вероятно, разовьется заболевание сердца (13 в классе 0 и 155 в классе 1).

Используя один и тот же набор данных в двоичном формате (болезнь сердца или отсутствие болезни сердца), некоторые показали точность около 65% в прогнозировании заболеваемости сердечными заболеваниями [5]. Важно помнить об этой «базовой» точности прогноза, чтобы установить реалистичные ожидания в отношении результатов модели. Чтобы продолжать улучшать модель, которая может точно предсказывать сердечные заболевания и их тяжесть, было бы полезно иметь больший набор данных с большим количеством функций.

Полный код можно найти здесь: https://github.com/sheenstar/Springboard_Intensive/blob/master/Capstone_project/Capstone_Final_HeartDisease_Code.ipynb

[1] CardioSmart: https://www.cardiosmart.org/Heart-Basics/CVD-Stats

[2] Фонд CDC: http://www.cdcfoundation.org/pr/2015/heart-disease-and-stroke-cost-america-nearly-1-billion-day-medical-costs-lost-productivity

[3] Уилсон, П. В. Ф., Р. Б. Д'Агостино, Д. Леви, А. М. Беланджер, Х. Зильбершатц и В. Б. Каннел. Прогнозирование ишемической болезни сердца с использованием категорий факторов риска. Тираж 97, вып. 18 (1998): 1837–847. doi: 10.1161/01.cir.97.18.1837.

[4] AnalyticsVidhya: https://www.analyticsvidhya.com/blog/2015/07/dimension-reduction-methods/

[5] http://www.becomingadatascientist.com/2015/01/19/data-science-practice-classifying-heart-disease/