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

Примечание. Я предлагаю вам прочитать Линейная регрессия, прежде чем продолжить этот блог.

Оглавление

  • Что такое логистическая регрессия?
  • Визуализация набора данных
  • Гипотеза и функция стоимости
  • Обучение модели с нуля
  • Оценка модели
  • Реализация Scikit-learn

Что такое логистическая регрессия?

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

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

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

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

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

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

Мы можем видеть, что значение сигмовидной функции всегда находится между 0 и 1. Значение точно 0,5 при X = 0. Мы можем использовать 0,5 в качестве порога вероятности для определения классов. Если вероятность больше 0,5, мы классифицируем ее как Класс-1 (Y = 1) или как Класс-0 (Y = 0).

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

  • Зависимая переменная должна быть категориальной.
  • Независимые переменные (признаки) должны быть независимыми (во избежание мультиколлинеарности).

Набор данных

Данные, используемые в этом блоге, взяты из курса Эндрю Нг Машинное обучение на Coursera. Данные можно скачать здесь. Данные состоят из оценок за два экзамена для 100 абитуриентов. Целевое значение принимает двоичные значения 1,0. 1 означает, что абитуриент был принят в университет, а 0 означает, что абитуриент не поступил. Цель состоит в том, чтобы построить классификатор, который может предсказать, будет ли заявка принята в университет или нет.

Давайте загрузим данные в pandas Dataframe с помощью функции read_csv. Мы также разделим данные на admitted и non-admitted для визуализации данных.

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

Гипотеза и функция стоимости

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

Модель линейной регрессии может быть представлена ​​уравнением.

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

где сигмовидная функция представлена ​​как,

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

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

Функция стоимости

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

Функция стоимости для одного обучающего примера может быть задана как:

Интуиция функции затрат

Если фактический класс равен 1, а модель предсказывает 0, мы должны серьезно наказать его, и наоборот. Как видно из рисунка ниже, для графика -log(h(x)), когда h (x) приближается к 1, стоимость равна 0, а когда h (x) приближается к 0, стоимость равна бесконечности (то есть мы сильно штрафуем модель). Аналогично для графика -log(1-h(x)), когда фактическое значение равно 0, а модель предсказывает 0, стоимость равна 0, а стоимость становится бесконечной, когда h (x) приближается к 1.

Мы можем объединить оба уравнения, используя:

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

где m - количество обучающих выборок.

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

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

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

Теперь у нас есть все необходимое для построения нашей модели. Давайте реализуем это в коде.

Давайте сначала подготовим данные для нашей модели.

X = np.c_[np.ones((X.shape[0], 1)), X]
y = y[:, np.newaxis]
theta = np.zeros((X.shape[1], 1))

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

def sigmoid(x):
    # Activation function used to map any real value between 0 and 1
    return 1 / (1 + np.exp(-x))

def net_input(theta, x):
    # Computes the weighted sum of inputs
    return np.dot(x, theta)

def probability(theta, x):
    # Returns the probability after passing through sigmoid
    return sigmoid(net_input(theta, x))

Затем мы определяем cost и gradient функцию.

def cost_function(self, theta, x, y):
    # Computes the cost function for all the training samples
    m = x.shape[0]
    total_cost = -(1 / m) * np.sum(
        y * np.log(probability(theta, x)) + (1 - y) * np.log(
            1 - probability(theta, x)))
    return total_cost

def gradient(self, theta, x, y):
    # Computes the gradient of the cost function at the point theta
    m = x.shape[0]
    return (1 / m) * np.dot(x.T, sigmoid(net_input(theta,   x)) - y)

Давайте также определим функцию fit, которая будет использоваться для поиска параметров модели, которые минимизируют функцию стоимости. В этом блоге мы написали метод градиентного спуска для вычисления параметров модели. Здесь мы будем использовать функцию fmin_tnc из библиотеки scipy. Его можно использовать для вычисления минимума для любой функции. Он принимает аргументы как

  • func: функция для минимизации
  • x0: начальные значения для параметров, которые мы хотим найти
  • fprime: градиент для функции, определенной параметром «func»
  • args: аргументы, которые необходимо передать функциям.
def fit(self, x, y, theta):
    opt_weights = fmin_tnc(func=cost_function, x0=theta,
                  fprime=gradient,args=(x, y.flatten()))
    return opt_weights[0]
parameters = fit(X, y, theta)

Параметры модели [-25.16131856 0.20623159 0.20147149]

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

Построение границы принятия решения

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

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

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

x_values = [np.min(X[:, 1] - 5), np.max(X[:, 2] + 5)]
y_values = - (parameters[0] + np.dot(parameters[1], x_values)) / parameters[2]

plt.plot(x_values, y_values, label='Decision Boundary')
plt.xlabel('Marks in 1st Exam')
plt.ylabel('Marks in 2nd Exam')
plt.legend()
plt.show()

Похоже, наша модель неплохо справилась с предсказанием классов. Но насколько это точно? Давайте разберемся.

Точность модели

def predict(self, x):
    theta = parameters[:, np.newaxis]
    return probability(theta, x)
def accuracy(self, x, actual_classes, probab_threshold=0.5):
    predicted_classes = (predict(x) >= 
                         probab_threshold).astype(int)
    predicted_classes = predicted_classes.flatten()
    accuracy = np.mean(predicted_classes == actual_classes)
    return accuracy * 100
accuracy(X, y.flatten())

Точность модели 89%.

Давайте реализуем наш классификатор с помощью scikit-learn и сравним его с моделью, которую мы построили с нуля.

реализация scikit-learn

from sklearn.linear_model import LogisticRegressionfrom sklearn.metrics import accuracy_score 
model = LogisticRegression()
model.fit(X, y)
predicted_classes = model.predict(X)
accuracy = accuracy_score(y.flatten(),predicted_classes)
parameters = model.coef_

Параметры модели [[-2.85831439, 0.05214733, 0.04531467]], точность 91%.

Почему параметры модели значительно отличаются от модели, которую мы реализовали с нуля? Если вы посмотрите документацию реализации логистической регрессии sk-learn, она учитывает регуляризацию . По сути, регуляризация используется для предотвращения переобучения модели данными. Я не буду вдаваться в подробности регуляризации в этом блоге. Но пока это все. Спасибо за прочтение !!

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

Пожалуйста, напишите мне, если вы где-то застряли или у вас есть отзывы.

Что дальше?

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

Посмотрите это место, чтобы узнать больше.