Во время магистерской программы по бизнес-аналитике в Саффолкском университете у нас был вводный курс по Python как его неотъемлемой части в анализе данных. Мы рассмотрели среду разработки Python, синтаксис и основы. Затем исследовательский анализ данных и проверка гипотез с помощью библиотеки pandas. После всех основ мы погрузились в основные статистические концепции и модели, такие как линейная регрессия, разделение обучения и тестирования, компромисс смещения и дисперсии, K-ближайшие соседи (KNN) и классификация. Затем мы рассмотрели логистическую регрессию, дерево решений и, в конце, поработали с API данных и познакомились с временными рядами. Нашей основной книгой было Введение в машинное обучение с помощью Python Андреаса К. Мюллера и Сары Гвидо.

В этой статье будет описан мой последний проект, который я завершил в конце этого курса. Проект основан на двух исследованиях Построение моделей прогнозирования риска для диабета 2 типа с использованием методов машинного обучения Се З., Николаева О., Луо Дж., Ли Д.» и Разработка моделей прогнозирования риска для диабета 2 типа: систематический обзор методологии и отчетности. Коллинз Г.С., Маллетт С., Омар Омар, Ю Л.М.».

Данные для анализа получены из Системы наблюдения за поведенческими факторами риска (BRFSS), которая собирает данные телефонных опросов жителей США, связанных со здоровьем. В качестве файлов данных исследования BRFSS, представленных в форматах, отличных от формата csv, я использовал работу Winston Larson на github, где он проделал обширную работу по извлечению и очистке данных BRFSS.

Исходные данные содержат 279 переменных и 464 644 записи за 2014 год. На основе упомянутых выше рецензируемых статей я выбрал 26 основных личных и общих характеристик, связанных со здоровьем, таких как общее состояние здоровья, ИМТ, возраст, время сна и т. д. Целевая переменная представляет собой двоичный код. классификация ответов Да или Нет на вопрос Говорили ли вам когда-нибудь, что у вас диабет? вопрос. Исходный код можно посмотреть по этой ссылке.

Уборка

На первом этапе мы отбираем людей моложе 30 лет, у которых может быть диабет 1 типа, беременных и людей с преддиабетом, которые не являются нашей основной задачей. На следующем шаге мы навсегда отбрасываем значения NA, и у нас остается 143 383 наблюдения для нашего анализа, и мы запускаем функцию describe для проверки сводной статистики для наших данныхafterЗначения NA удалены. Кроме того, мы строим гистограмму для каждой переменной, чтобы проверить, нормально ли они распределены.

# Dropping permanently NA values and run summary statistics
df.dropna(inplace=True)
df.describe()
df.hist(figsize=(20,20))

Следующий шаг, чтобы проверить, сбалансированы ли наши данные, рекомендуется, когда наша целевая переменная имеет более низкую относительную частоту для одного класса, чем для другого (больше людей ответят Нет, чем Да на наш главный вопрос «Говорили ли вам когда-нибудь, что у вас диабет?»)

# Is our data balanced? It is!
df.diabete3.value_counts(normalize=True)

Приведенная выше функция value_counts из библиотеки Pandas создает отношение, содержащее количество уникальных значений. В нашем случае это дает нам следующее соотношение: 0,83 человека ответили Нет и 0,16 человека ответили Да. Рекомендуется иметь пропорцию баланса около 10 % или использовать метод повторной выборки, основанный на книге Дэниела Т. Лароуза Discovering Knowledge in Data — An Introduction to Data Mining.

После того, как мы убедились, что наши данные сбалансированы, имея пропорцию 16%, мы назначаем наши функции (личную информацию и информацию о здоровье) X, а нашу целевую переменную (ответ «Да» или «Нет») — Y.

feature_cols =['genhlth','age','bmi_class','checkup1','income2','race','mscode','flushot6','employ1','sex','marital','education','sleptim1','cvdcrhd4','hlthcvr1','menthlth','chckidny','useequip','exercise','addepev2','renthom1','exerany2','blind','decide','hlthpln1','smoker']

X = df[feature_cols]
y = df.diabete3

Создание обучающих и тестовых данных

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

X_train, X_test, y_train, y_test = train_test_split(X,y, random_state = 50, test_size=0.3)

Модель дерева решений

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

# Make a decision tree and train
tree = DecisionTreeClassifier(random_state=50)
# Train tree
tree.fit(X_train, y_train)

Затем мы используем нашу подобранную модель для прогнозирования с помощью функции predict из библиотеки Sikit-learn. Эта функция берет подогнанные данные и предсказывает метку для новых данных. Другая функция, predict_proba, находит вероятность для каждого класса.

# Using fitted model and Make predictions
X_train_tree_predictions = tree.predict(X_train)
X_train_tree_probs = tree.predict_proba(X_train)[:, 1]
tree_predictions = tree.predict(X_test)
tree_probs = tree.predict_proba(X_test)[:, 1]

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

# Calculate ROC AUC
roc_value = roc_auc_score(y_test, tree_probs)

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

feature_tree = pd.DataFrame({'Feature': feature_cols,
                   'Importance': tree.feature_importances_}).\
                    sort_values('Importance', ascending = False)

Последним шагом будет завершение выборочного теста, такого как перекрестная проверка (CV), чтобы определить окончательную оценку нашей модели. Для этого шага мы используем функцию cross_val_score, устанавливаем k-folds равным 10 и вычисляем среднее значение этих оценок перекрестной проверки. В нашем случае оценка составляет 0,76, что соответствует точности 76%.

scores = cross_val_score(tree, X, y, cv=10, scoring= 'accuracy')
np.mean(scores)

Модель случайного леса

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

# Create the model with 100 trees
model = RandomForestClassifier(n_estimators=100, max_features='sqrt', oob_score=True, random_state=50, n_jobs=-1, verbose = 1)

#Fit the Model on Training data
model.fit(X_train, y_train)

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

#Using fitted model, make predictions
X_train_rf_predictions = model.predict(X_train)
X_train_rf_probs = model.predict_proba(X_train)[:, 1]

rf_predictions = model.predict(X_test)
rf_probs = model.predict_proba(X_test)[:, 1]

Следующим шагом будет вычисление ROC AUC на основе наших прогнозируемых показателей с помощью функции roc_auc_score. В этой модели ROC AUC составляет 0,78, что выше, чем в модели дерева решений.

# Calculate ROC AUC
roc_value = roc_auc_score(y_test, rf_probs)

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

# Compute feature importances
feature_model = pd.DataFrame({'Feature': feature_cols,
                   'importance': model.feature_importances_}).\
                    sort_values('importance', ascending = False)

Последним шагом будет запуск перекрестной проверки (CV), чтобы определить окончательную оценку нашей модели. В модели случайного леса точность составляет 0,84, что выше, чем в простой модели дерева решений, на 8%.

scores = cross_val_score(model, X, y, cv=10, scoring= 'accuracy')
np.mean(scores)

Спасибо, что прочитали или завершили проект вместе со мной! Я был бы очень признателен за ваши отзывы в комментариях или примеры других используемых моделей. Любые вопросы и критика приветствуются!

использованная литература

[1] Се З., Николаева О., Луо Дж., Ли Д. Построение моделей прогнозирования риска для диабета 2 типа с использованием методов машинного обучения. Предыдущий Хронический Дис 2019;16:190109. DOI: значок http://dx.doi.org/10.5888/pcd16.190109external.

[2] Коллинз Г.С., Маллет С., Омар О., Ю. Л.М. Разработка моделей прогнозирования риска для диабета 2 типа: систематический обзор методологии и отчетности. BMC Med 2011;9(1):103. https://bmcmedicine.biomedcentral.com/articles/10.1186/1741-7015-9-103

[3] Ларсон В. Взгляд на здоровье и поведение с использованием данных CDC. https://github.com/winstonlarson/brfss

[4] Нельсон Дж. Деревья решений. Взято из главы 8 книги Введение в статистическое обучение. http://faculty.marshall.usc.edu/gareth-james/