Логистическая регрессия: основы
Понимание основ методов логистической регрессии
Вступление
Логистическая регрессия - это метод моделирования вероятности события. Как и линейная регрессия, он помогает понять взаимосвязь между одной или несколькими переменными и целевой переменной, за исключением того, что в этом случае наша целевая переменная является двоичной: ее значение равно 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 здесь.