Логистическая регрессия: основы

Понимание основ методов логистической регрессии

Вступление

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

С учетом сказанного, структура логистической регрессии также похожа на структуру модели линейной регрессии: у вас есть набор независимых переменных (X1, X2…) и наша целевая двоичная переменная (Y). Однако стоящая за ним функция немного сложнее:

P (Y = 1) представляет собой вероятность того, что ваш Y равен 1, в то время как b0 - это параметр, не связанный с X, а B - вектор коэффициентов, которые представляют отношения между Y и каждым из X1, X2 и так далее.

Затем логистическая регрессия оценит значения параметров b, которые лучше соответствуют вашим данным, обычно с использованием метода максимального правдоподобия. Когда у нас есть эти оценки, мы можем рассчитать P (Y = 1) для новых точек данных и либо придерживаться этой вероятности, либо использовать ее для классификации этих наблюдений на основе порогового значения (например: если вероятность того, что кто-то болен раком легких, больше чем 50%, мы можем сделать обоснованное предположение, что оно у них будет).

Чтобы лучше понять разницу между линейной и логистической регрессией, представьте, что мы нанесли переменную рака легких по оси Y (Y = 1, если у пациента рак легких, и 0 в противном случае), а возраст пациента - по оси X. Ниже представлены строки, полученные в результате каждой регрессии. Какой из них кажется более подходящим для наших данных?

Начинаем пачкать руки

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

Давайте сначала посмотрим на доступные переменные:

IN:
path = 'insert you file path here'
data = read.csv(paste(path,'train.csv', sep = ""))
colnames(data)
OUT:
 [1] "PassengerId" "Survived"    "Pclass"      "Name"        "Sex"         "Age"         "SibSp"      
 [8] "Parch"       "Ticket"      "Fare"        "Cabin"       "Embarked"

Итак, помимо идентификатора, у нас есть некоторая, возможно, полезная информация о них, такая как их класс на корабле (1-й, 2-й или 3-й) и их пол.

Очистка данных

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

IN:
data$Age[is.na(data$Age)] = median(data$Age,na.rm=T)
data$Pclass = as.factor(data$Pclass)

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

Разделение на тренировку / тест

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

IN:
train = data[1:700,]
test = data[701:889,]

Моделирование

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

IN:
model = glm(Survived ~ Pclass + Sex + Age,
             family = binomial(link = 'logit'), data = train)
summary(model)
OUT:
Call:
glm(formula = Survived ~ Pclass + Sex + Age, family = binomial(link = "logit"), 
    data = train)
Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-2.5352  -0.7055  -0.4390   0.6186   2.3728
Coefficients:
             Estimate Std. Error z value Pr(>|z|)    
(Intercept)  3.226908   0.398636   8.095 5.73e-16 ***
Pclass2     -0.908714   0.288174  -3.153 0.001614 ** 
Pclass3     -2.153203   0.268262  -8.026 1.00e-15 ***
Sexmale     -2.603025   0.209018 -12.454  < 2e-16 ***
Age         -0.027199   0.008157  -3.334 0.000855 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 934.43  on 699  degrees of freedom
Residual deviance: 645.20  on 695  degrees of freedom
AIC: 655.2
Number of Fisher Scoring iterations: 4

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

glm (Выжившие ~ Класс + Пол + Возраст, семья = биномиальная (ссылка = 'логит'), данные = поезд)

Мы начали с вызова функции glm, которая используется для подгонки обобщенных линейных моделей. Чтобы он работал именно как логистическая регрессия, мы установили family = binomial и link = 'logit'. Для нашей проблемы мы также могли бы установить ссылку на ' probit ' или' cochit ', но мы будем придерживаться функции logit. Разница между ними в основном теоретическая, и их результаты обычно довольно похожи.

Coefficients:
             Estimate Std. Error z value Pr(>|z|)    
(Intercept)  3.226908   0.398636   8.095 5.73e-16 ***
Pclass2     -0.908714   0.288174  -3.153 0.001614 ** 
Pclass3     -2.153203   0.268262  -8.026 1.00e-15 ***
Sexmale     -2.603025   0.209018 -12.454  < 2e-16 ***
Age         -0.027199   0.008157  -3.334 0.000855 ***

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

Здесь коэффициент Intercept - это b0, а другие коэффициенты - это вектор B. Наша модель будет выглядеть так (я округлил коэффициенты для лучшей читаемости):

Где Pclass2 = 1, если пассажир принадлежал к классу 2, и 0 в противном случае (аналогично для других переменных, за исключением возраста, который равен фактическому возрасту пассажира). Помимо того, что они являются частью нашего вероятностного уравнения, они также помогают нам интерпретировать шансы: коэффициент -2,6 для Sexmale означает, что шансы на выживание, когда вы мужчина, равны exp (-2,6) = 0,07 раза шансы выжить, когда ты женщина.

Другой важный столбец в этой таблице - Pr (›| z |), который мы называем p-значением. Это показывает нам, насколько мы уверены в значимости оценочного коэффициента (чем он ближе к нулю, тем мы уверены). Если бы у нас были коэффициенты с высокими p-значениями, нам, вероятно, не следует включать связанные переменные в нашу модель.

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

Теперь давайте попробуем вторую модель, добавив переменную Fare (сколько пассажир заплатил за билет):

IN:
model2 = glm(Survived ~ Pclass + Sex + Age + Fare,
 family = binomial(link = ‘logit’), data = train)
summary(model2)
OUT:
Call:
glm(formula = Survived ~ Pclass + Sex + Age + Fare, family = binomial(link = "logit"), 
    data = train)
Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-2.5225  -0.7060  -0.4382   0.6187   2.3749
Coefficients:
              Estimate Std. Error z value Pr(>|z|)    
(Intercept)  3.2957397  0.4738515   6.955 3.52e-12 ***
Pclass2     -0.9500899  0.3265572  -2.909 0.003621 ** 
Pclass3     -2.2016346  0.3229743  -6.817 9.31e-12 ***
Sexmale     -2.6085804  0.2100784 -12.417  < 2e-16 ***
Age         -0.0275303  0.0082521  -3.336 0.000849 ***
Fare        -0.0006707  0.0024848  -0.270 0.787211    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 934.43  on 699  degrees of freedom
Residual deviance: 645.13  on 694  degrees of freedom
AIC: 657.13
Number of Fisher Scoring iterations: 4

Обратите внимание на то, что p-значение для Fare высокое, что означает, что это не значимая переменная, и что AIC увеличился, что означает немного худшую модель. Одна из возможностей состоит в том, что, поскольку мы уже учитываем класс пассажира, в стоимость билета не добавляется много новой информации. Чтобы проверить это, давайте запустим третью модель с тарифом, но без Pclass:

IN:
model3 = glm(Survived ~  Sex + Age + Fare,
             family = binomial(link = 'logit'), data = train)
summary(model3)
OUT:
Call:
glm(formula = Survived ~ Sex + Age + Fare, family = binomial(link = “logit”), 
 data = train)
Deviance Residuals: 
 Min 1Q Median 3Q Max 
-2.2015 -0.6174 -0.5889 0.8093 1.9786
Coefficients:
 Estimate Std. Error z value Pr(>|z|) 
(Intercept) 0.835415 0.250798 3.331 0.000865 ***
Sexmale -2.429141 0.192294 -12.632 < 2e-16 ***
Age -0.005092 0.007294 -0.698 0.485142 
Fare 0.009933 0.002412 4.119 3.81e-05 ***
 — -
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 934.43 on 699 degrees of freedom
Residual deviance: 701.47 on 696 degrees of freedom
AIC: 709.47
Number of Fisher Scoring iterations: 4

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

Давайте теперь применим нашу первую модель, которая показала лучшие результаты, чем две следующие, к тестовой выборке, чтобы увидеть, как она работает:

IN:
predictions = ifelse(predict(model, newdata = test) > 0.5, 1, 0)
accuracy = mean(predictions == test$Survived)
print(paste(‘Accuracy :’, accuracy))
OUT:
"Accuracy : 0.825396825396825"

Мы начали с применения нашей модели к набору тестов и утверждения, что пассажир выжил, если рассчитанная вероятность больше 0,5. Первым показателем, который мы рассчитали, была точность, которая представляет собой соотношение правильных прогнозов. Точность 0,82 означает, что наши прогнозы верны в 82% случаев. Неплохо, правда? Смотря как. Представьте, что 99% пассажиров погибли. Тогда мы могли бы предсказать, что все пассажиры погибли, и наша точность была бы 99%, не нуждаясь в модели для этого. Поэтому нужно как-то учитывать соотношение выживших в наших метриках. Вот тут-то и пригодятся кривая ROC и AUC.

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

Для выполнения этих вычислений в R нам понадобится пакет ROCR:

IN:
library(ROCR)
probabilities = predict(model, newdata = test)
prediction_object = prediction(probabilities, test$Survived)
roc = performance(prediction_object, measure = "tpr", x.measure = "fpr")
plot(roc)
OUT:

Чем больше площадь под кривой, тем лучше наша модель, поэтому нам нужно, чтобы кривая проходила как можно ближе к верхнему левому углу графика. Обратите внимание на наш код, как мы создали его с помощью функции performance () и использовали «fpr» для x.measure и «tpr» для измерения. FPR означает ложноположительную ставку, а TPR - истинно положительную ставку. Чтобы вычислить AUC, мы снова используем функцию performance (), но на этот раз мы вводим «auc» в качестве меры:

IN:
perf_auc = performance(prediction_object, measure = “auc”)
auc = [email protected][[1]]
print(paste(‘AUC :’, auc))
OUT:
"AUC : 0.863385354141657"

У нас AUC 0,86, что неплохо для задачи классификации.

Заключение

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

Вы можете получить доступ к полному сценарию R здесь.