Что в этом посте? В Части 1 этого поста мы (Усман Раза, Харман Шах Сингх, Чинг-Йи Линь и Рохан Кар ») описал проблему повторной госпитализации и то, как мы подготовили набор данных для моделирования повторной госпитализации. В этой второй и заключительной части мы опробуем некоторые модели и попытаемся понять полученные результаты.

Примечание: полный код и файлы данных теперь доступны на Git-hub здесь.

Наборы функций для моделирования

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

На данный момент все эти функции присутствуют во фрейме данных. Итак, в python определение определенного набора функций - это просто объявление переменной списка, содержащей эти столбцы:

feature_set_1 = ['age', 'time_in_hospital', 'num_procedures', 'num_medications', 'number_outpatient_log1p', 'number_emergency_log1p', 'number_inpatient_log1p', 'number_diagnoses', 'metformin', 'repaglinide', 'nateglinide', 'chlorpropamide', 'glimepiride', 'glipizide', 'glyburide', 'pioglitazone', 'rosiglitazone', 'acarbose', 'tolazamide', 'insulin', 'glyburide-metformin', 'race_AfricanAmerican', 'race_Asian', 'race_Caucasian', 'race_Hispanic', 'race_Other', 'gender_1', 'admission_type_id_3', 'admission_type_id_5', 'discharge_disposition_id_2', 'discharge_disposition_id_7', 'discharge_disposition_id_10', 'discharge_disposition_id_18', 'admission_source_id_4', 'admission_source_id_7', 'admission_source_id_9', 'max_glu_serum_0', 'max_glu_serum_1', 'A1Cresult_0',  'A1Cresult_1', 'num_medications|time_in_hospital', 'num_medications|num_procedures',  'time_in_hospital|num_lab_procedures', 'num_medications|num_lab_procedures', 'num_medications|number_diagnoses', 'age|number_diagnoses', 'change|num_medications', 'number_diagnoses|time_in_hospital', 'num_medications|numchange', 'level1_diag1_1.0', 'level1_diag1_2.0', 'level1_diag1_3.0', 'level1_diag1_4.0',  'level1_diag1_5.0','level1_diag1_6.0', 'level1_diag1_7.0', 'level1_diag1_8.0']
feature_set_2 = ['age', 'time_in_hospital', 'num_lab_procedures', 'num_procedures', 'service_utilization_log1p', 'number_diagnoses', 'nummed', 'race_AfricanAmerican', 'race_Asian', 'race_Caucasian', 'race_Hispanic', 'race_Other', 'gender_1', 'A1Cresult_0', 'A1Cresult_1', 'admission_type_id_3', 'admission_type_id_4', 'admission_type_id_5', 'discharge_disposition_id_2', 'discharge_disposition_id_7', ‘discharge_disposition_id_10', 'discharge_disposition_id_18', 'admission_source_id_4', 'admission_source_id_7', 'admission_source_id_8', 'admission_source_id_9', 'admission_source_id_11', 'numchange', 'num_medications|time_in_hospital', 'num_medications|num_procedures', 'time_in_hospital|num_lab_procedures', 'num_medications|num_lab_procedures', 'num_medications|number_diagnoses', 'age|number_diagnoses', 'change|num_medications', 'number_diagnoses|time_in_hospital', 'num_medications|numchange', 'level1_diag1_1.0', 'level1_diag1_2.0', 'level1_diag1_3.0', 'level1_diag1_4.0', 'level1_diag1_5.0', 'level1_diag1_6.0', 'level1_diag1_7.0', 'level1_diag1_8.0']

Затем, когда нам нужно использовать конкретный набор для моделирования, нам просто нужно выбрать этот набор столбцов из полного фрейма данных, как показано здесь:

train_input = df[feature_set_1]
train_output = df['readmitted']

Выбор моделей

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

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

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

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

Мы не использовали следующие типы моделей:

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

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

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

4. Нейронные сети. Опять же, они могут давать очень точные результаты (при условии, что функции содержат прогностическую информацию), но в значительной степени им не хватает интерпретируемости.

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

Разделение данных и обеспечение надежных прогнозов

Мы рандомизировали (чтобы избежать какой-либо систематической ошибки выбора) и разделили чистые данные, полученные из Части 1, на две части: обучающие и тестовые данные в соотношении 80:20, что позволило нам обучить наши модели на 80% данных и использовать другие 20% для оценки производительности наших моделей. Более того, мы использовали 25-кратную перекрестную проверку наших обучающих данных, чтобы убедиться, что наши модели были масштабируемыми и надежными, а также не допускали чрезмерного соответствия обучающим данным. Мы также позаботились о том, чтобы модели обучались и оценивались на одних и тех же данных, чтобы обеспечить сравнение производительности моделей для одних и тех же данных, на которых обучаются и оцениваются.

Как получить и интерпретировать результаты моделей

Логистическая регрессия и деревья решений принципиально различаются по своей интерпретации, поэтому мы рассмотрим их результаты отдельно. Однако, прежде чем применять модели, помните, что нам нужно выполнить некоторую балансировку данных (объясняется в части 1):

from imblearn.over_sampling import SMOTE
from collections import Counter
print('Original dataset shape {}'.format(Counter(train_output)))
smt = SMOTE(random_state=20)
train_input_new, train_output_new = smt.fit_sample(train_input, train_output)
print('New dataset shape {}'.format(Counter(train_output_new)))
Original dataset shape Counter({0: 56476, 1: 5199})
New dataset shape Counter({0: 56476, 1: 56476})

Теперь мы можем приступить к применению моделей.

Логистическая регрессия

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

import statsmodels.api as sm
from sklearn.model_selection import train_test_split
X_train, X_dev, Y_train, Y_dev = train_test_split(train_input_new, train_output_new, test_size=0.20, random_state=0)
logit = sm.Logit(Y_train, X_train)
result = logit.fit()
print(result.summary())

Последнее утверждение дает нам сводку модели вместе с коэффициентами. Приведенная ниже версия усечена, так как она довольно длинная:

Поскольку существует слишком много переменных и коэффициентов, на которые нужно смотреть, мы можем немного упростить задачу, выбрав только те коэффициенты, которые имеют p-значение

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

EXP (Coefficient of age) = EXP (Log of unit odds change)
= EXP (0.25) = 1.28
But remember Age was standardized and 1 SD of Age = 15 years
Therefore:
For every 15 years increase in age, there is 28% increase in Odds of being readmitted versus not being readmitted!

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

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

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

Помимо просмотра коэффициентов, нам также необходимо увидеть, насколько хорошо модель работает с точки зрения точности и ошибок. Для этого мы тестируем его, используя 20% тестовую выборку, и используем 10-кратную перекрестную проверку, как показано здесь:

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
X_train, X_dev, Y_train, Y_dev = train_test_split(train_input_new, train_output_new, test_size=0.20, random_state=0)
logreg = LogisticRegression(fit_intercept=True, penalty='l1')
print("Cross Validation Score: {:.2%}".format(np.mean(cross_val_score(logreg, X_train, Y_train, cv=10))))
logreg.fit(X_train, Y_train)
print("Dev Set score: {:.2%}".format(logreg.score(X_dev, Y_dev)))

Что дает нам:

Cross Validation Score: 61.10%
Dev Set score: 60.62%

Мы также можем взглянуть на матрицу путаницы и использовать библиотеку метрик scikit-learn для расчета нескольких показателей точности:

Y_dev_predict = logreg.predict(X_dev)
pd.crosstab(pd.Series(Y_dev, name = 'Actual'), pd.Series(Y_dev_predict, name = 'Predict'), margins = True)
from sklearn.metrics import accuracy_score, precision_score, recall_score, roc_auc_score
print("Accuracy is {0:.2f}".format(accuracy_score(Y_dev, Y_dev_predict)))
print("Precision is {0:.2f}".format(precision_score(Y_dev, Y_dev_predict)))
print("Recall is {0:.2f}".format(recall_score(Y_dev, Y_dev_predict)))
print("AUC is {0:.2f}".format(roc_auc_score(Y_dev, Y_dev_predict)))
Accuracy is 0.61
Precision is 0.62
Recall is 0.55
AUC is 0.61

Как мы видим, точность модели составляет 61% (то есть ошибка классификации 39%) для сложного набора функций с отзывом 55%. Аналогичный анализ с использованием сокращенного набора функций дает почти такие же результаты. На данный момент кажется, что модель не очень хорошо работает с точки зрения точности и показателей ошибок. Здесь можно было бы сделать больше, но давайте перейдем к деревьям решений.

Деревья решений

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

train_input = df_pd[feature_set_1_no_int]
train_output = df_pd['readmitted']
# Data balancing applied using SMOTE
from imblearn.over_sampling import SMOTE
from collections import Counter
print('Original dataset shape {}'.format(Counter(train_output)))
smt = SMOTE(random_state=20)
train_input_new, train_output_new = smt.fit_sample(train_input, train_output)
print('New dataset shape {}'.format(Counter(train_output_new)))
train_input_new = pd.DataFrame(train_input_new, columns = list(train_input.columns))
X_train, X_dev, Y_train, Y_dev = train_test_split(train_input_new, train_output_new, test_size=0.20, random_state=0)
Original dataset shape Counter({0: 56476, 1: 5199})
New dataset shape Counter({0: 56476, 1: 56476})

Теперь, чтобы применить классификатор дерева решений с помощью scikit-learn:

from sklearn.tree import DecisionTreeClassifier
dte = DecisionTreeClassifier(max_depth=28, criterion = "entropy", min_samples_split=10)
print("Cross Validation score: {:.2%}".format(np.mean(cross_val_score(dte, X_train, Y_train, cv=10))))
dte.fit(X_train, Y_train)
print("Dev Set score: {:.2%}".format(dte.score(X_dev, Y_dev)))
Cross Validation score: 91.03%
Dev Set score: 91.17%

Это уже отлично выглядит! Но давайте посчитаем и другие показатели:

Y_dev_predict = dte.predict(X_dev)
pd.crosstab(pd.Series(Y_dev, name = 'Actual'), pd.Series(Y_dev_predict, name = 'Predict'), margins = True)
from sklearn.metrics import accuracy_score, precision_score, recall_score, roc_auc_score
print("Accuracy is {0:.2f}".format(accuracy_score(Y_dev, Y_dev_predict)))
print("Precision is {0:.2f}".format(precision_score(Y_dev, Y_dev_predict)))
print("Recall is {0:.2f}".format(recall_score(Y_dev, Y_dev_predict)))
print("AUC is {0:.2f}".format(roc_auc_score(Y_dev, Y_dev_predict)))
Accuracy is 0.91
Precision is 0.93
Recall is 0.89
AUC is 0.91

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

Но это еще не все, что мы можем получить от деревьев решений. Каждый узел дерева указывает решение о разделении данных, которое приближает нас к прогнозированию повторного доступа. Задача состоит в том, чтобы визуализировать глубокие деревья с множеством узлов. Итак, для простоты давайте визуализируем только первые два уровня этого дерева решений с помощью библиотеки GraphViz:

import graphviz
from IPython.display import Image
import pydotplus
from sklearn import tree
dot_dt_q2 = tree.export_graphviz(dte, out_file="dt_q2.dot", feature_names=X_train.columns, max_depth=2, class_names=["No","Readm"], filled=True, rounded=True, special_characters=True)
graph_dt_q2 = pydotplus.graph_from_dot_file('dt_q2.dot')
Image(graph_dt_q2.create_png())

Глядя на это, мы можем сказать, что первая особенность, используемая при принятии решения о том, будет ли пациент повторно госпитализирована или нет, заключается в том, будет ли пациент выписан в другую больницу или учреждение (категория разряда_disposition_id_2…). На следующем уровне дерева показана эта же функция, повторяющаяся с одной стороны, и дни, проведенные в больнице, с другой. А так нет. Но это может легко запутать, поэтому мы хотели бы как-то резюмировать эту информацию. «Важность функции» - один из распространенных способов сделать это:

# Shot top most features based on importance
feature_names = X_train.columns
feature_imports = dte.feature_importances_
most_imp_features = pd.DataFrame([f for f in zip(feature_names,feature_imports)], columns=["Feature", "Importance"]).nlargest(10, "Importance")
most_imp_features.sort_values(by="Importance", inplace=True)
plt.figure(figsize=(10,6))
plt.barh(range(len(most_imp_features)), most_imp_features.Importance, align='center', alpha=0.8)
plt.yticks(range(len(most_imp_features)), most_imp_features.Feature, fontsize=14)
plt.xlabel('Importance')
plt.title('Most important features - Decision Tree (entropy) (Question 2 - complex model)')
plt.show()

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

Случайный лес

Леса состоят из деревьев. Случайные леса состоят из случайно выращенных деревьев. На жаргоне машинного обучения этот метод означает, что вместо того, чтобы полагаться на одно дерево решений, мы пробуем много разных деревьев со случайно назначенными подмножествами функций. Окончательный прогноз затем вычисляется путем голосования по прогнозам, сделанным всеми деревьями в лесу. Шаги кодирования для случайного леса по существу аналогичны шагам для деревьев решений, за исключением того, что мы должны использовать классификатор случайного леса из sklearn:

from sklearn.ensemble import RandomForestClassifier

После применения случайного леса мы получаем точность 94% независимо от использования функции Джини или энтропии. Важность функций при использовании этих двух функций различается незначительно, и ниже мы показываем функцию с функцией Джини:

Когда мы повторяем этот процесс для более простой модели, мы получаем аналогичную точность (~ 94%), но значения основных функций немного отличались по сравнению со сложной моделью:

Итак, какой вывод?

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

Сравнение производительности модели

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

Ограничения

Имеющийся набор данных предоставляет действительно полезную информацию, как демографическую, так и оценочную, о повторной госпитализации пациентов. Однако важно понимать, что качество прогнозов зависит не только от объема имеющихся данных, но и от их разнообразия. Мы ограничены имеющейся информацией, которая представляет собой исчерпывающий, но не исчерпывающий отчет обо всех факторах, которые могут повлиять на повторную госпитализацию. Помимо других факторов, упомянутых выше, набор данных не включает многие важные факторы, такие как доступ к медицинской помощи, которая, как было показано в одном исследовании, составляет 58% вариативных показателей повторной госпитализации. В зависимости от ситуации может быть много других факторов, которые могут повлиять на повторную госпитализацию. Более того, доступность данных за более длительные периоды времени также может существенно повлиять на производительность моделей. Хотя высокая производительность частично объясняется синтетическими данными, созданными с помощью SMOTE, мы можем сказать, что производительность будет примерно такой же, в пределах консервативных оценок ошибок, для реальных данных. . Недостаточная выборка будет предпочтительным методом, если доступен достаточно большой набор данных. Логистическая модель показала плохое значение Pseudo R-Squared, что может указывать на большой шум в данных, но это не лучший показатель соответствия логистическим моделям. На самом деле, некоторые исследователи вообще не сообщают это значение для логистических моделей. , чтобы избежать путаницы. Тем не менее, эффекты по-прежнему статистически значимы на основе тестов отношения правдоподобия для обоих.

И что?

То, что мы здесь сделали, - это лишь верхушка айсберга. Есть еще много методов, которые можно попробовать, параметров, которые нужно уточнить, и методов выбора функций, которые нужно использовать. Можно также представить дополнение набора данных некоторой внешней информацией для его улучшения. Однако мы можем кое-что сказать об общем процессе:

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

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