Логистическая регрессия: строим модель с нуля на Sigmoid и Log Loss
В этой статье поговорим о классификации и одной из базовых моделей — Логистической регрессии.
Сегодня всё чаще обсуждают сложные модели: нейронные сети, LLM, генеративный ИИ и так далее. Но при решении реальных задач уже много лет используется и до сих пор не теряет актуальности модель под названием Logistic Regression.
Возникает вопрос: почему в эпоху столь сложных моделей логистическая регрессия всё ещё так широко применяется?
Дело в том, что в реальных бизнес-задачах цель не всегда сводится только к точному прогнозу. Иногда не менее важно понимать, почему модель приняла именно такое решение.
Например, при оценке кредитного риска модели недостаточно просто сказать, что клиент рискованный. Нам также важно понимать, какие факторы повлияли на этот вывод больше всего: доход, текущие долги, кредитная история или что-то ещё.
Именно здесь и раскрывается одно из главных преимуществ логистической регрессии. Модель имеет относительно простую структуру, быстро обучается, а её результаты легко интерпретировать. Глядя на веса признаков, можно понять, в какую сторону и насколько сильно каждый из них влияет на решение модели.
Поэтому простая модель — далеко не всегда слабая модель. На практике, в зависимости от требований задачи, более простая и объяснимая модель может оказаться удачнее сложной.
Более сложная модель ≠ более качественная модель.
А теперь давайте разберёмся, как логистическая регрессия принимает свои решения — с самого начала.
Когда нужно определить, спам ли пришедшее письмо, или доброкачественная ли опухоль, мы имеем дело с задачей классификации. Такие задачи можно свести к обозначениям 1 и 0: при выполнении определённых условий результат обозначается как 1 (злокачественная) или 0 (доброкачественная).

Также встречается и многоклассовая классификация:

Нажмите Enter или кликните, чтобы посмотреть изображение полностью

В этой статье мы рассмотрим бинарную классификацию. Возьмём такую задачу:
Нажмите Enter или кликните, чтобы посмотреть изображение полностью

Предположим, у нас есть такие данные. Попробуем подойти к этой задаче с логикой линейной регрессии:
Нажмите Enter или кликните, чтобы посмотреть изображение полностью

Как видно, с помощью простой линейной модели нам удалось разделить два класса. Возьмём произвольное значение 0.5 и, сравнивая с ним результаты регрессии, сможем чётко классифицировать данные.
Теперь предположим, что данные другие: чем больше опухоль, тем выше вероятность её злокачественности. Рассмотрим на простом примере:
Нажмите Enter или кликните, чтобы посмотреть изображение полностью

В этом случае модель нужно обновить. Например, можно получить такую модель:
Нажмите Enter или кликните, чтобы посмотреть изображение полностью

Допустим, нам удалось провести примерно такую линию, и линейная регрессия сработала удачно. Но если мы попробуем разделить классы, сравнивая с 0.5, то некоторые единицы окажутся ниже 0.5 и будут классифицированы как 0. Хотя на самом деле мы видим, что они равны 1. Значит, с помощью линейной функции хорошую классификацию провести не получается. Следовательно, нужно изменить саму функцию.
То есть нам нужно изменить функцию гипотезы. Поскольку речь идёт о бинарной классификации (0 и 1), нам нужны значения именно между 0 и 1.

Для этого мы воспользуемся сигмоидной функцией.

Сигмоидная функция зависит от переменной z. Наша же функция гипотезы зависит от входов X и их весов. Поэтому подставляем это выражение вместо z.

График функции выглядит следующим образом:
Нажмите Enter или кликните, чтобы посмотреть изображение полностью

Как видно, когда значение z стремится к плюс бесконечности, результат приближается к 1, а когда стремится к минус бесконечности — к 0.
Допустим, мы произвели расчёт и получили значение гипотезы 0.8. Это означает, что с вероятностью 80% y=1. Если рассматривать это как вероятность, то фактически мы вычисляем вероятность того, что y=1 при известных X и w. Тогда это можно записать так:

Тогда можно также вычислить вероятность того, что y=0, и сумма обеих вероятностей всегда будет равна 1:
Нажмите Enter или кликните, чтобы посмотреть изображение полностью

Возвращаясь к нашему примеру: если вероятность y=1 была 0.8, то вероятность y=0 составит 0.2.
Тогда это можно записать в общем виде — так, как мы уже рассматривали формулу Бернулли:

Выше мы выбрали порог (threshold) 0.5, но его можно менять в зависимости от задачи. Если увеличить порог с 0.5 до 0.6, для отнесения примера к классу y=1 потребуется более высокая вероятность. Из-за этого модель будет реже присваивать примерам класс y=1.
Если посмотреть на график z, сравнение функции гипотезы с 0.5 равносильно сравнению самого z с 0. Посмотрим на график:

Запишем в виде формулы:

Decision boundary
Предположим, мы провели вычисления и получили следующие веса:
w₀=-3, w₁=1, w₂=1. Это фактически означает: если -3+x₁+x₂≥0, то y=1. То есть если x₁+x₂≥3, то y=1. Посмотрим на графике:
Нажмите Enter или кликните, чтобы посмотреть изображение полностью

В функции гипотезы выше мы производили расчёт только для одной строки — то есть определяли значение (1 или 0) только для первого примера. А что если примеров много? Речь идёт об одновременном определении класса для нескольких примеров. Формула будет выглядеть так:
Функция правдоподобия (Likelihood function)
Нажмите Enter или кликните, чтобы посмотреть изображение полностью

Теперь построим график этой функции:

На этот раз, как видно, нам нужно максимизировать функцию. Поэтому мы воспользуемся методом «Gradient Ascent». Запишем формулу:

Чтобы упростить вычисления, возьмём логарифм от функции L. Тогда формула примет следующий вид:
Нажмите Enter или кликните, чтобы посмотреть изображение полностью

Тогда функцию потерь (cost function) можно записать так:
Нажмите Enter или кликните, чтобы посмотреть изображение полностью

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

Тогда это можно записать и так:

Следовательно,

Также посмотрим на производную логарифма:

Теперь мы можем рассмотреть производную функции l:
Нажмите Enter или кликните, чтобы посмотреть изображение полностью

Раскрыв производную, получим следующее:

Нажмите Enter или кликните, чтобы посмотреть изображение полностью

Раскрыв скобки, получим следующее:
Нажмите Enter или кликните, чтобы посмотреть изображение полностью




Теперь, опираясь на всё это, напишем код на Python:
df=pd.read_csv("datasets/diabetes.csv")
X=df.drop("Outcome", axis=1)
X = np.c_[np.ones(X.shape[0]), X]
n, m=X.shape
y=np.array(df['Outcome']).reshape(-1, 1)
w=np.zeros((m, 1))
alpha=0.01
epochs=1000
def sigmoid_function(X, w):
y_pred= 1/(1 + np.exp(-np.dot(X, w)))
return y_pred
for epoch in range(epochs):
y_pred=sigmoid_function(X, w)
J=(-1/n) * ( np.dot(y.T, np.log(y_pred)) + np.dot((1-y).T, np.log(1-y_pred)) )
dw=((-1/n)* np.dot(X.T, (y-y_pred)))
w=w-alpha*dwТеперь, используя полученные веса w, вычислим предсказания модели:
def accuracy(y, y_pred):
return (y==y_pred).mean()
y_pred=sigmoid_function(X, w)
y_pred=(y_pred >= 0.5).astype(int)
print(accuracy(y, y_pred))
Теперь воспользуемся классом LogisticRegression из библиотеки sklearn:
from sklearn.linear_model import LogisticRegression
X=df.drop("Outcome", axis=1)
y=df["Outcome"]
log_reg=LogisticRegression()
log_reg.fit(X, y)
y_pred=log_reg.predict(X)
print(accuracy_score(y, y_pred))
print(accuracy_score(y, y_pred))
В итоге, логистическая регрессия — это один из базовых алгоритмов машинного обучения, применяемых в задачах классификации, который представляет результат в виде вероятности. Модель преобразует результат линейной комбинации в вероятностное значение от 0 до 1 с помощью сигмоидной функции, а затем на основе установленного порога (threshold) определяет итоговый класс. Чтобы модель обучилась подходящим весам, минимизируется функция потерь Log Loss (Binary Cross-Entropy), а веса итеративно обновляются с помощью градиентного спуска. Несмотря на простую и легко интерпретируемую структуру, логистическая регрессия по-прежнему широко применяется в задачах классификации благодаря вероятностному подходу и способности строить границу решения (decision boundary).
1 человек прочитал эту статью
Комментарии
Войдите, чтобы оставить комментарий. Войти