Сначала поговорим о данных. Данные можно загрузить из базы данных Kaggle, при условии, что у вас есть учетная запись Kaggle. Целью данных является прогнозирование потенциальных случаев диабета на основе определенных диагностических мер. Все опрошенные - женщины не моложе 21 года индейского происхождения пима.

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

В приведенном выше уравнении Pᵢ — это вероятность диабета у пациента i. β — коэффициенты модели LR, а x — характеристики выборки данных i.

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

Сначала загрузите важные пакеты библиотек.

library(cdata)    # data wrangling
library(ggplot2)  # elegant plots
library(knitr)    # display table 
library(reshape2) # data wrangling
library(WVPlots)  # ROC plot, double density plot and etc

Затем загрузите данные в рабочую среду (не забудьте указать рабочий каталог, в котором находится файл, либо с помощью синтаксиса setwd(), либо нажав 'Ctrl + Shift + H'). Просмотр статистических сводок по каждому признаку и их типам переменных (например, непрерывным, логическим, категориальным). Всего имеется 768 образцов (субъектов) и 9 переменных (8 атрибутов и цель).

data=read.csv(‘diabetes.csv’)
summary(data)
str(data)

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

Фрагменты кода ниже показывают количество положительных случаев (диабет) по сравнению с количеством отрицательных случаев данных. Данные состоят из 268 положительных случаев, а остальные 500 — отрицательные.

data$Outcome=as.factor(data$Outcome)
summary(data$Outcome)

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

# for reproducibility
set.seed(123)
randn=runif(nrow(data))
train_idx=randn<=0.8  # Roughly 80% training data, 20% test data
train=data[train_idx,]
test=data[!train_idx,]

Визуализация данных

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

target=’Outcome’
vars=setdiff(colnames(train),target)
# moving data from wide to tall form (be careful with the #indentation
data_long=unpivot_to_blocks(data,nameForNewKeyColumn = “variables”,
 nameForNewValueColumn = “values”,columnsToTakeFrom = vars)
# plot the histogram
ggplot(data_long,aes(x=values)) + 
 geom_histogram(bins=10,fill=”gray”) +
 facet_wrap(~variables,ncol = 3,scales=”free”)

Сгруппированная диаграмма — еще один отличный инструмент визуализации для отображения распределения переменных для каждого класса.

# boxplot for each variables with regards to group
ggplot(data_long,aes(x=Outcome,y=values)) +
 geom_boxplot(color=”blue”,fill=”blue”,alpha=0.2,notch=TRUE,
 outlier.color=”red”,outlier.fill = “red”,outlier.size = 2) +
 facet_wrap(~variables,ncol = 3,scales = “free”)

Из приведенных выше диаграмм видно, что переменная «Глюкоза» обычно выше среди тех, у кого диагностирован диабет, поскольку отметки двух классов не перекрываются. Тем не менее, важно обратить внимание на наличие выбросов. Это же обстоятельство проявляется и в возрасте, беременностях и предикторах ИМТ.

Матрица корреляции также полезна для выявления (линейной) связи между двумя переменными, как показано на тепловой карте ниже. Возраст положительно коррелирует с числом беременностей с коэффициентом корреляции Пирсона 0,57.

cormat=cor(train[,vars]) # correlation matrix
cormat[upper.tri(cormat)]=NA 
melted_cormat=melt(cormat,na.rm = TRUE)
# heat-map
ggplot(data=melted_cormat,aes(Var1,Var2,fill=value)) +
 geom_tile(color=’white’) +
 scale_fill_gradient2(low = “blue”, high=”red”,mid=”white”,midpoint = 0,
 limit=c(-1,1),space = “Lab”,name=”Correlation”) +
 theme_minimal()+
 theme(axis.text.x = element_text(angle = 45,vjust = 1,size = 12,hjust = 1)) +
 coord_fixed() +
 geom_text(aes(Var1,Var2,label=round(value,2)),color=”black”,size=3)

# plot grouped scatter plot
# Create the plots
pairs(data[,vars], pch=20,cex=0.3,col=data$Outcome, 
 lower.panel = NULL)

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

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

Обучение LR-модели можно выполнить с помощью синтаксиса glm(), задав аргумент: family=binomial("logit"). Логистическая регрессия предполагает линейность между независимыми переменными и логарифмическими шансами. Несмотря на это теоретическое ограничение, коэффициенты параметрической модели могут дать представление о взаимосвязи между отдельными атрибутами и шансами/вероятностью положительных результатов (диабет).

model=glm(Outcome~.,data=train,family = binomial(“logit”))
summary(model)

Большинство коэффициентов статистически значимы, за исключением «Толщины кожи» и «Инсулина». Как мы можем интерпретировать коэффициенты модели? Возьмем в качестве примера «ИМТ». Оценка коэффициента 0,095 указывает на то, что логарифмическая вероятность увеличится на 9,5%, если ИМТ увеличится на 1 единицу. Тогда как насчет того, чтобы вместо этого мы захотели узнать вероятность? Предположим, что вероятность того, что у человека будет диагностирован диабет, равна 0,25, что произойдет с вероятностью того, что у него будет диагностирован диабет, если ИМТ увеличится на 1, а другие переменные останутся неизменными? Давайте поработаем с математикой.

Так, увеличение ИМТ на единицу повысит вероятность возникновения диабета с 0,25 до 0,2682. Этот же расчет применим и к другим переменным. Несмотря на то, что интерпретация не так проста, как линейная регрессия, она позволяет нам получить представление о вкладе каждого предиктора в реакцию.

Оценка модели

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

# prediction
train$pred=predict(model,newdata = train,type = “response”)
test$pred=predict(model,newdata=test,type=”response”)
# confusion matrix
(confmat_test=table(truth=test$Outcome,predict=test$pred>0.5))
(acc_test=sum(diag(confmat_test))/sum(confmat_test))
(precision=confmat_test[2,2]/sum(confmat_test[,2]))
(recall=confmat_test[2,2]/sum(confmat_test[2,]))

Производительность модели оценивалась с использованием тестовых данных: точность: 0,7355, точность: 0,7083 и полнота: 0,5574. Кроме того, производительность модели можно визуализировать с помощью кривой рабочих характеристик приемника (ROC) и графика двойной плотности, как показано во фрагменте кода и графических выходных данных ниже.

plt=DoubleDensityPlot(test,xvar = “pred”,truthVar = “Outcome”,
 title = “Distribution of scores of LR model in test data”)
plt+geom_vline(xintercept = 0.5, color=”red”,linetype=2)

test$Outcome_numeric=as.numeric(test$Outcome)-1
ROCPlot(test,xvar=’pred’,truthVar = “Outcome_numeric”,
 truthTarget = TRUE,
 title = “Logistic regression test performance”)

Точная настройка

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

train$Outcome_numeric=as.numeric(train$Outcome)-1
plt=PRTPlot(test,’pred’,’Outcome_numeric’,TRUE,
 plotvars = c(‘enrichment’,’recall’),
 thresholdrange = c(0,1),
 title = ‘Enrichment/recall vs threshold for LR model’)
plt+geom_vline(xintercept = 0.375,color=”red”,linetype=2)

# Confusion matrix of test data
(confmat_test=table(truth=test$Outcome,predict=test$pred>0.375))
(acc_test=sum(diag(confmat_test))/sum(confmat_test))
(precision=confmat_test[2,2]/sum(confmat_test[,2]))
(recall=confmat_test[2,2]/sum(confmat_test[2,]))

Этот новый порог дает нам лучшую производительность обобщения с точки зрения точности и полноты, но небольшое снижение точности: точность: 0,7548, точность: 0,6825 и полнота: 0,7049. Однако следует помнить, что если модель применяется к будущим данным с очень другим распределением, чем ее обучающие данные, модель будет работать хуже.

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