Логистическая регрессия | Оптимизация

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

Все курсы > Оптимизация > Занятие 5

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

Содержание занятия

Бинарная логистическая регрессия

Задача бинарной классификации

Вернемся к задаче кредитного скоринга, про которую мы говорили, когда обсуждали принцип машинного обучения. Предположим, что мы собрали данные и выявили зависимость возвращения кредита (ось y) от возраста заемщика (ось x).

зависимость возвращения кредита от возраста заемщика

Как мы видим, в среднем более молодые заемщики реже возвращают кредит. Возникает вопрос, с помощью какой модели можно описать эту зависимость? Казалось бы, можно построить линейную регрессию таким образом, чтобы она выдавала некоторое значение и, если это значение окажется ниже 0,5 — отнести наблюдение к классу 0, если выше — к классу 1.

применение линейной регрессии к задаче классификации
  • Если $ f_w(x) < 0,5 \rightarrow \hat{y} = 0 $
  • Если $ f_w(x) \geq 0,5 \rightarrow \hat{y} = 1 $

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

применение линейной регрессии к задаче классификации 2

Теперь часть наблюдений, принадлежащих к классу 1, будет ошибочно отнесено моделью к классу 0.

Кроме этого, линейная регрессия по оси y выдает значения, сильно выходящие за пределы интересующего нас интервала от нуля до единицы.

Откроем ноутбук к этому занятию

Функция логистической регрессии

Сигмоида

Возможное решение упомянутых выше сложностей — пропустить значение линейной регрессии через сигмоиду (sigmoid function), которая при любом значении X не выйдет из необходимого нам диапазона $0 \leq h(x) \leq 1 $. Напомню формулу и график сигмоиды.

$$ g(z) = \frac{1}{1+e^{-z}} $$

график сигмоиды

Примечание: обратие внимание, когда z представляет собой большое отрицательное число, знаменатель становится очень большим $ 1 + e^{-(-5)} \approx 148, 413 $ и значение сигмоиды стремится к нулю; когда z является большим положительным числом, знаменатель, а вместе с ним и все выражение стремятся к единице $ 1 + e^{-(5)} \approx 0,0067 $.

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

$$ z = X\theta \rightarrow h_{\theta}(x) = \frac{1}{1+e^{-(X\theta)}} $$

В этом смысле никакой ошибки в названии «логистическая регрессия» нет. Этот алгоритм решает задачу классификации через модель линейной регрессии.

Если вы не помните, почему мы записали множественную линейную функцию как $\theta x$, посмотрите предыдущую лекцию.

Приведем код на Питоне.

Теперь посмотрим, как интерпретировать коэффициенты.

Интерпретация коэффициентов

Для любого значения x через $ h_{\theta}(x) $ мы будем получать вероятность от 0 до 1, что объект принадлежит к классу y = 1. Например, если класс 1 означает, что заемщик вернул кредит, то $ h_{\theta}(x) = 0,8 $ говорит о том, что согласно нашей модели (с параметрами $\theta$), для данного заемщика (x) вероятность возвращения кредита состаляет 80 процентов.

В общем случае мы можем записать вероятность вот так.

$$ h_{\theta}(x) = P(y = 1 | x; \theta) $$

Это выражение можно прочитать как вероятность принадлежности к классу 1 при условии x с параметрами $\theta$ (probability of y = 1 given x, parameterized by $\theta$).

Поскольку, как мы помним, сумма вероятностей событий, образующих полную группу, всегда равна единице, вероятность принадлежности к классу 0 будет равна

$$ P(y = 0 | x; \theta) = 1-P(y = 1 | x; \theta) $$

Решающая граница

Решающая граница (decision boundary) — это порог, который определяет к какому классу отнести то или иное наблюдение. Если выбрать порог на уровне 0,5, то все что выше или равно этому порогу мы отнесем к классу 1, все что ниже — к классу 0.

$$ y = 1, h_{\theta}(x) \geq 0,5 $$

$$ y = 0, h_{\theta}(x) < 0,5 $$

Теперь обратите внимание на сигмоиду. Сигмоида $ g(z) $ принимает значения больше 0,5, если $ z \geq 0 $, а так как $ z = X\theta $, то можно сказать, что

  • $h_{\theta}(x) \geq 0,5$ и $ y = 1$, когда $ X\theta \geq 0 $, и соответственно
  • $h_{\theta}(x) \ < 0,5 $ и $ y = 0$, когда $ X\theta < 0 $.
Уравнение решающей границы

Предположим, что у нас есть два признака $x_1$ и $x_2$. Вместе они образуют так называемое пространство ввода (input space), то есть все имеющиеся у нас наблюдения. Мы можем представить это пространство на координатной плоскости, дополнительно выделив цветом наблюдения, относящиеся к разным классам.

Кроме того, представим, что мы уже построили модель логистической регрессии, и она провела для нас соответствующую границу между двумя классами.

пространство ввода

Возникает вопрос. Как, зная коэффициенты $\theta_0$, $\theta_1$ и $\theta_2$ модели, найти уравнение линии решающей границы? Для начала договоримся, что уравнение решающией границы будет иметь вид $x_2 = mx_1 + c$, где m — наклон прямой, а c — сдвиг.

Теперь вспомним, что модель с двумя признаками (до подачи в сигмоиду) имеет вид

$$ z = \theta_0 + \theta_1 x_1 + \theta_2 x_2 $$

Также не забудем, что граница проходит там, где $ h_{\theta}(x) = 0,5 $, а значит z = 0. Значит,

$$ 0 = \theta_0 + \theta_1 x_1 + \theta_2 x_2 $$

Чтобы найти с (то есть сдвиг линии решающей границы вдоль оси $x_2$) приравняем $x_1$ к нулю и решим для $x_2$ (именно эта точка и будет сдвигом c).

$$ 0 = \theta_0 + 0 + \theta_2 x_2 \rightarrow x_2 = -\frac{\theta_0}{\theta_2} \rightarrow c = -\frac{\theta_0}{\theta_2} $$

Теперь займемся наклоном m. Возьмем некоторую точку на линии решающей границы с координатами $(x_1^a, x_2^a)$, $(x_1^b, x_2^b)$. Тогда наклон m будет равен

$$ m = \frac{x_2^b-x_2^a}{x_1^b-x_1^a} $$

Так как эти точки расположены на решающей границе, то справедливо, что

$$ 0 = \theta_1x_1^b + \theta_2x_2^b + \theta_0-(\theta_1x_1^a + \theta_2x_2^a + \theta_0) $$

$$ -\theta_2(x_2^b-x_2^a) = \theta_1(x_1^b-x_1^a) $$

А значит,

$$ \frac{x_2^b-x_2^a}{x_1^b-x_1^a} = -\frac{\theta_1}{\theta_2} \rightarrow m = -\frac{\theta_1}{\theta_2} $$

Вычислительная устойчивость сигмоиды

При очень больших отрицательных или положительных значениях z может возникнуть переполнение памяти (overflow).

Преодолеть это ограничение и добиться вычислительной устойчивости (numerical stability) алгоритма можно с помощью следующего тождества.

$$ g(z) = \frac{1}{1+e^{-z}} = \frac{1}{1+e^{-z}} \times \frac{e^z}{e^z} = \frac{e^z}{e^z(1+e^{-z})} = \frac {e^z}{e^z + 1} $$

Что интересно, первая часть тождества устойчива при очень больших положительных значениях z.

При этом вторая стабильна при очень больших отрицательных значениях.

Объединим обе части с помощью условия.

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

Можно также использовать функцию expit() библиотеки scipy.

Остается написать линейную функцию и подать ее результат в сигмоиду.

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

пример расчета логистической функции для четырех наблюдений и трех коэффициентов

Пропишем это на Питоне.

Модель работает корректно. Теперь обсудим, как ее обучать, то есть какую функцию потерь использовать для оптимизации параметров $\theta$.

Logistic loss или функция кросс-энтропии

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

сравнение выпуклой и невыпуклой функций

Вместо MSE мы будем использовать функцию логистической ошибки, которую еще называют функцией бинарной кросс-энтропии (log loss, binary cross-entropy loss).

График и формула функции логистической ошибки

Вначале посмотрим на нее на графике.

функция логистической ошибки

Разберемся, как она работает. Наша модель $h_{\theta}(x)$ может выдавать вероятность от 0 до 1, фактические значения $y$ только 0 и 1.

Сценарий 1. Предположим, что для конкретного заемщика в обучающем датасете истинное значение/ целевой класс записан как 1 (то есть заемщик вернул кредит). Тогда «срабатывает» синяя ветвь графика и ошибка измеряется по ней. Соответственно, чем ближе выдаваемая моделью вероятность к единице, тем меньше ошибка.

$$ -log(P(y = 1 | x; \theta)) = -log(h_{\theta}(x)), y = 1 $$

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

$$ -log(1-P(y = 1 | x; \theta)) = -log(1-h_{\theta}(x)), y = 0 $$

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

В итоге нам нужно будет найти сумму вероятностей принадлежности к классу 1 для сценария 1 и сценария 2.

$$ J(\theta) = \begin{cases} -log(h_{\theta}(x)) | y=1 \\ -log(1-h_{\theta}(x)) | y=0 \end{cases} $$

Однако, для каждого наблюдения нам нужно учитывать только одну из вероятностей (либо $y=1$, либо $y=0$). Как нам переключаться между ними? На самом деле очень просто.

В качестве переключателя можно использовать целевую переменную. В частности, умножим левую часть функции на $y$, а правую на $1-y$. Тогда, если речь идет о классе 1, первая часть умножится на единицу, вторая на ноль и исчезнет. Если речь идет о классе 0, произойдет обратное, исчезнет левая часть, а правая останется. Получается

$$ J(\theta) = -\frac{1}{n} \sum y \cdot log(h_{\theta}(x)) + (1-y) \cdot log(1-h_{\theta}(x)) $$

Рассмотрим ее работу на учебном примере.

Расчет логистической ошибки

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

целевая переменная и прогноз модели логистической регрессии

Найдем вероятность принадлежности к классу 1.

вероятность принадлежности к классу 1

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

отрицательный логарифм вероятности

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

функция логистической ошибки (y = 1)

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

Окончательный вариант

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

Проверим ее работу на учебных данных.

Теперь займемся поиском производной.

Производная функции логистической ошибки

Предположим, что $G(\theta)$ — одна из частных производных описанной выше функции логистической ошибки $J(\theta)$,

$$ G = y \cdot log(h) + (1-y) \cdot log(1-h) $$

где h — это сигмоида $1/1+e^{-z}$, а $z(\theta)$ — линейная функция $x\theta$. Тогда по chain rule нам нужно найти производные следующих функций

$$ \frac{\partial G}{\partial \theta} = \frac{\partial G}{\partial h} \cdot \frac{\partial h}{\partial z} \cdot \frac{\partial z}{\partial \theta} $$

Производная логарифмической функции

Начнем с производной логарифмической функции.

$$ \frac{\partial}{\partial x} ln f(x) = \frac{1}{f(x)} $$

Теперь, помня, что x и y — это константы, найдем первую производную.

$$ \frac{\partial G}{\partial h} \left[ y \cdot log(h) + (1-y) \cdot log(1-h) \right] $$

$$ = y \cdot \frac{\partial G}{\partial h} [log(h)] + (1-y) \cdot \frac{\partial G}{\partial h} [log(1-h)] $$

$$ = \frac{1}{h}y + \frac{1}{1-h} \cdot \frac{\partial G}{\partial h} [1-h] \cdot (1-y) $$

Упростим выражение (не забыв про производную разности).

$$ = \frac{h}{y} + \frac{\frac{\partial G}{\partial h} (1-h) (1-y)}{1-h} = \frac{h}{y}+\frac{(0-1)(1-y)}{1-h} $$

$$ = \frac{y}{h}-\frac{1-y}{1-h} = \frac{y-h}{h(1-h)} $$

Теперь займемся производной сигмоиды.

Производная сигмоиды

Вначале упростим выражение.

$$ \frac{\partial h}{\partial z} \left[ \frac{1}{1+e^{-z}} \right] = \frac{\partial h}{\partial z} \left[ (1+e^{-z})^{-1}) \right] $$

Теперь перейдем к нахождению производной

$$ = -(1+e^{-z})^{-2}) \cdot (-e^{-z}) = \frac{e^{-z}}{(1+e^{-z})^2} $$

$$ = \frac{1}{1+e^{-z}} \cdot \frac{e^{-z}}{1+e^{-z}} = \frac{1}{1+e^{-z}} \cdot \frac{(1+e^{-z})-1}{1+e^{-z}} $$

$$ = \frac{1}{1+e^{-z}} \cdot \left( \frac{1+e^{-z}}{1+e^{-z}}-\frac{1}{1+e^{-z}} \right) $$

$$ = \frac{1}{1+e^{-z}} \cdot \left( 1-\frac{1}{1+e^{-z}} \right) $$

В терминах предложенной выше нотации получается

$$ h(1-h) $$

Производная линейной функции

Наконец найдем производную линейной функции.

$$ \frac{\partial z}{\partial \theta} = x $$

Перемножим производные и найдем градиент по каждому из признаков j для n наблюдений.

$$ \frac{\partial J}{\partial \theta} = \frac{y-h}{h(1-h)} \cdot h(1-h) \cdot x_j \cdot \frac{1}{n} = x_j \cdot (y-h) \cdot \frac{1}{n} $$

Замечу, что хотя производная похожа на градиент функции линейной регрессии, на самом деле это разные функции, $h$ в данном случае сигмоида.

Для нахождения градиента (всех частных производных одновременно) перепишем формулу в векторной нотации.

$$ \nabla_{\theta} J = X^T(h(X\theta)-y) \times \frac{1}{n} $$

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

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

Объявим соответствующую функцию.

На всякий случай напомню, что прогнозные значения (y_pred) мы получаем с помощью объявленной ранее функции $h(x, thetas)$.

Подготовка данных

В качестве примера возьмем встроенный в sklearn датасет, в котором нам предлагается определить класс вина по его характеристикам.

датасет о вине
Выше представлена только часть датасета. Полностью его можно посмотреть в ноутбуке⧉.

Целевая переменная

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

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

Отбор признаков

Наша целевая переменная выражена бинарной категорией или, как еще говорят, находится на дихотомической шкале (dichotomous variable). В этом случае применять коэффициент корреляции Пирсона не стоит и можно использовать точечно-бисериальную корреляцию (point-biserial correlation). Рассчитаем корреляцию признаков и целевой переменной нашего датасета.

точечно-бисериальная корреляция

Наиболее коррелирующим с целевой переменной признаком является пролин (proline). Визуально оценим насколько сильно отличается этот показатель для классов вина 0 и 1.

класс вина и пролин

Теперь посмотрим на зависимость двух признаков (спирт и пролин) от целевой переменной.

зависимость признаков от целевой переменной

В целом можно сказать, что классы линейно разделимы (другими словами, мы можем провести прямую между ними). Поместим признаки в переменную X, а целевую переменную — в y.

Масштабирование признаков

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

стандартизация данных

Проверим результат.

Теперь мы готовы к созданию и обучению модели.

Обучение модели

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

Применим ее к нашему датафрейму с признаками.

добавление признака x0

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

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

Теперь выполним основную работу по минимизации функции потерь и поиску оптимальных весов (выполнение кода ниже у меня заняло около 30 секунд).

Посмотрим на получившиеся веса и финальный уровень ошибки.

Модель обучена. Теперь мы можем сделать прогноз и оценить результат.

Прогноз и оценка качества

Прогноз модели

Объявим функцию predict(), которая будет предсказывать к какому классу относится то или иное наблюдение. От функции $h(x, thetas)$ эта функция будет отличаться тем, что выдаст не только вероятность принадлежности к тому или иному классу, но и непосредственно сам предполагаемый класс (0 или 1).

Вызовем функцию predict() и запишем прогноз класса и вероятность принадлежности к этому классу в переменные y_pred и probs соответственно.

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

Метрика accuracy и матрица ошибок

Оценим результат с помощью метрики accuracy и матрицы ошибок.

матрица ошибок

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

Решающая граница

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

график решающей границы модели

На графике хорошо видны те пять значений, в которых ошибся наш классификатор.

Написание класса

Остается написать класс бинарной логистической регрессии.

Проверим работу написанного нами класса. Вначале подготовим данные и обучим модель.

Затем сделаем прогноз и оценим качество модели.

матрица ошибок (класс логистической регрессии)

Модель показала точно такой же результат. Методы класса LogReg работают. Теперь давайте сравним работу нашего класса с классом LogisticRegression библиотеки sklearn.

Сравнение с sklearn

Обучение модели

Вначале обучим модель.

Прогноз

Теперь необходимо сделать прогноз и найти соответствующие вероятности. В классе LogisticRegression библиотеки sklearn метод .predict() отвечает за предсказание принадлежности к определенному классу, а метод .predict_proba() отвечает за вероятность такого прогноза.

Модель предсказала для первого наблюдения класс 0. При этом, обратите внимание, что метод .predict_proba() для каждого наблюдения выдает две вероятности, первая — это вероятность принадлежности к классу 0, вторая — к классу 1.

Оценка качества

Рассчитаем метрику accuracy.

И построим матрицу ошибок.

матрица ошибок (класс LogisticRegression в sklearn)

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

Решающая граница

Построим решающую границу.

решающая граница (класс LogisticRegression в sklearn)

Бинарная полиномиальная регрессия

Идея бинарной полиномиальной логистической регрессии (binary polynomial logistic regression) заключается в том, чтобы использовать полином внутри сигмоиды и соответственно создать нелинейную границу между двумя классами.

нелинейная граница между двумя классами

Полиномиальные признаки

Уравнение полинома на основе двух признаков будет выглядеть следующим образом.

$$ y = \theta_{0}x_0 + \theta_{1}x_1 + \theta_{2}x_2 + \theta_{3} x_1^2 + \theta_{4} x_1x_2 + \theta_{5} x_2^2 $$

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

Теперь преобразуем наши данные так, как если бы мы использовали полином второй степени.

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

Сравним исходные признаки с полиномиальными.

первое наблюдение исходных признаков

Моделирование и оценка качества

Обучим модель, сделаем прогноз и оценим результат.

Построим матрицу ошибок.

матрица ошибок (полиномиальная логистическая регрессия)

Для того чтобы визуально оценить качество модели, построим два графика: фактических классов и прогнозных. Вначале создадим датасет, в котором будут исходные признаки (alcohol, proline) и прогнозные значения (y_pred).

прогнозы полиномиальной логистической регрессии
прогноз бинарной полиномиальной регрессии

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

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

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

Перейдем ко второй части нашего занятия.

Мультиклассовая логистическая регрессия

Как поступить, если нужно предсказать не два класса, а больше? Сегодня мы рассмотрим два подхода: one-vs-rest и кросс-энтропию. Начнем с того, что подготовим данные.

Подготовка данных

Вернем исходный датасет с тремя классами.

В целевой переменной большое двух классов, а значит точечно-бисериальный коэффициент корреляции мы использовать не можем. Воспользуемся корреляционным отношением (correlation ratio).

значение корреляционного отношения

Теперь наибольшую корреляцию с целевой переменной показывают флавоноиды (flavanoids) и пролин (proline). Их и оставим.

флавоноиды и пролин

Посмотрим, насколько легко можно разделить эти классы.

разделимость классов

Перейдем непосредственно к алгоритмам мультиклассовой логистической регрессии. Начнем с подхода one-vs-rest.

Подход one-vs-rest

подход one-vs-rest

Подход one-vs-rest или one-vs-all предполагает, что мы отделяем один класс, а остальные наоборот объединяем. Так мы поступаем с каждым классом и строим по одной модели логистической регрессии относительно каждого из класса. Например, если у нас три класса, то у нас будет три модели логистической регрессии. Далее мы смотрим на получившиеся вероятности и выбираем наибольшую.

$$ h_\theta^{(i)}(x) = P(y = i | x; theta), i \in \{0, 1, 2\} $$

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

Подготовка датасетов

подготовка данных в подходе one-vs-rest

Обучение моделей

Прогноз и оценка качества

Обратите внимание, при использовании подхода one-vs-rest вероятности в сумме не дают единицу.

матрица ошибок (подход one-vs-rest)

Сравним фактическое и прогнозное распределение классов на точечной диаграмме.

сравнение фактических классов с прогнозом модели one-vs-rest

Написание класса

Поместим достигнутый выше результат в класс.

Проверим класс в работе.

Сравнение с sklearn

Для того чтобы применить подход one-vs-rest в классе LogisticRegression, необходимо использовать значение параметра multi_class = ‘ovr’.

Мультиклассовая полиномиальная регрессия

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

Результат, по сравнению с моделью sklearn без полиномиальных признаков, стал чуть лучше. Однако это было достигнуто за счет полинома достаточно высокой степени (degree = 7), что неэффективно с точки зрения временной сложности алгоритма.

Посмотрим, какие нелинейные решающие границы удалось построить алгоритму.

полиномиальная мультиклассовая логистическая регрессия (подход one-vs-rest)

Softmax Regression

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

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

Подготовка признаков

Возьмем признаки flavanoids и proline и добавим столбец из единиц.

добавление признака x0

Кодирование целевой переменной

Напишем собственную функцию для one-hot encoding.

Такой же результат можно получить с помощью класса LabelBinarizer.

Инициализация весов

Создадим нулевую матрицу весов. Она будет иметь размерность: количество признаков (строки) х количество классов (столбцы). Приведем схематичный пример для четырех наблюдений, трех признаков (включая сдвиг $\theta_0$) и трех классов.

умножение матрицы признаков на матрицу весов

Инициализируем веса.

Функция softmax

Подробнее изучим функцию softmax. Приведем формулу.

$$ \text{softmax}(z)_{i} = \frac{e^{z_i}}{\sum_{k=1}^N e^{z_k}} $$

Рассмотрим ее реализацию на Питоне.

Напомню, что $ z = (-X\theta) $. Соответственно в нашем случае мы будем умножать матрицу 178 x 3 на 3 x 3.

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

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

Для того чтобы обеспечить вычислительную устойчивость softmax мы можем вычесть из z максимальное значение в каждой из 178 строк (пока что, опять же на первой итерации, оно равно нулю).

$$ \text{softmax}(z)_{i} = \frac{e^{z_i-max(z)}}{\sum_{k=1}^N e^{z_k-max(z)}} $$

Смысл такого преобразования⧉ в том, что оно делает значения z нулевыми или отрицательными.

Далее, число возводимое в увеличивающуюся отрицательную степень стремится к нулю, а не к бесконечности и, таким образом, не вызывает переполнения памяти. Найдем числитель и знаменатель из формулы softmax.

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

На первой итерации при одинаковых $\theta$ мы получаем, что логично, одинаковые вероятности принадлежности к каждому из классов. Напишем функцию.

Примечание. Обратите внимание, что сигмоида — это частный случай функции softmax для двух классов $[z_1, 0]$. Вероятность класса $z_1$ будет равна

$$ softmax(z_1) = \frac{e^{z_1}}{e^{z_1}+e^0} = \frac{e^{z_1}}{e^{z_1}+1} $$

Если разделить и числитель, и знаменатель на $e^{z_1}$, то получим

$$ sigmoid(z_1) = \frac{e^{z_1}}{1 + e^{-z_1}} $$

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

Теперь нужно понять, насколько сильно при таких весах ошибается наш алгоритм.

Функция потерь

Вспомним функцию бинарной кросс-энтропии. То есть функции ошибки для двух классов.

$$ L(y, \theta) = -\frac{1}{n} \sum y \cdot log(h_{\theta}(x)) + (1-y) \cdot log(1-h_{\theta}(x)) $$

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

$$ L(y_{ohe}, softmax) = -\sum y_{ohe} log(softmax) $$

Разберемся, что здесь происходит. $y_{ohe}$ содержит закодированную целевую переменную, например, для наблюдения класса 0 [1, 0, 0], softmax содержит вектор вероятностей принадлежности наблюдения к каждому из классов, например, [0,3 0,4 0,3] (мы видим, что алгоритм ошибается).

В данном случае закодированная целевая переменная также выступает в виде переключателя. Здесь при умножении «срабатывает» только первая вероятность $1 \times 0,3 + 0 \times 0,4 + 0 \times 0,4 $. Если подставить в формулу, то получаем (np.sum() добавлена для сохранения единообразия с формулой выше, в данном случае у нас одно наблюдение и сумма не нужна).

Если бы модель в своих вероятностях ошибалась меньше, то и общая ошибка была бы меньше.

Функция $-log$ позволяет снижать ошибку при увеличении вероятности верного (сохраненного переключателем) класса.

функция категориальной (многоклассовой) кросс-энтропии

Напишем функцию.

Рассчитаем ошибку для нулевых весов.

Для снижения ошибки нужно найти градиент.

Градиент

Приведем формулу градиента без дифференцирования.

$$ \nabla_{\theta}J = \frac{1}{n} \times X^T \cdot (y_{ohe}-softmax)  $$

По сути, мы умножаем транспонированную матрицу признаков (3 x 178) на разницу между закодированной целевой переменной и вероятностями функции softmax (178 x 3).

Обучение модели, прогноз и оценка качества

Выполним обучение модели.

Посмотрим на получившиеся коэффициенты (напомню, что первая строка матрицы это сдвиг (intercept, $\theta_0$)) и достигнутый уровень ошибки.

Сделаем прогноз и оценим качество.

матрица ошибок (softmax логистическая регрессия)

Написание класса

Объединим созданные выше компоненты в класс.

Обучим модель, сделаем прогноз и оценим качество.

Сравнение с sklearn

Для того чтобы использовать softmax логистическую регрессию в sklearn, соответствующему классу нужно передать параметр multi_class = ‘multinomial’.

Подведем итог

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

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

Рассмотрим обучение нейронных сетей.