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

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

[Статья по теме: Обработка отсутствующих данных в Python / Pandas]

Вкратце, идея, лежащая в основе процесса обучения логистической регрессии, состоит в том, чтобы максимизировать вероятность гипотезы о том, что данные разделены сигмоидом. Для этого необходимо найти оптимальные коэффициенты для сигмовидной функции (x) = 11 + e – x. Эти коэффициенты итеративно аппроксимируются с минимизацией функции потерь логистической регрессии с использованием градиентного спуска. Как только убытки достигают минимума или очень близки, мы можем использовать нашу модель для прогнозирования.

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

импортировать numpy как np

импортировать matplotlib.pyplot как plt

Мы также должны ввести набор данных. Здесь мы используем классический пример scikit-learn классификации рака груди, который часто используется для примеров машинного обучения «hello-world». Этот набор данных состоит из 569 обучающих выборок и включает 30 функций для двоичной классификации.

из sklearn.datasets импортировать load_breast_cancer

из sklearn.model_selection import train_test_split

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

data = load_breast_cancer () [‘data’]

target = load_breast_cancer () ["цель"]

Затем разделите все данные с метками на обучающую и тестовую выборки. Размер тестовой выборки должен составлять примерно 20–25% от всех данных. Мы используем этот образец, чтобы проверить результаты обучения и убедиться в отсутствии переобучения. Кроме того, мы перемешиваем данные, которые мы разделяем, чтобы убедиться, что обучающие и тестовые данные имеют одинаковое распределение.

X_train, X_test, y_train, y_test = train_test_split (данные, цель, test_size = 0,2, перемешать = True)

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

def сигмоид (x):

return np.maximum (np.minimum (1 / (1 + np.exp (-x)), 0,9999), 0,0001)

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

def cost_function (x, y, theta):

т = x.dot (тета)

return - np.sum (y * np.log (sigmoid (t)) + (1 - y) * np.log (1 - sigmoid (t))) / x.shape [0]

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

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

def gradient_cost_function (x, y, theta):

т = x.dot (тета)

вернуть x.T.dot (y - сигмоид (t)) / x.shape [0]

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

def update_theta (x, y, theta, learning_rate):

вернуть theta + learning_rate * gradient_cost_function (x, y, theta)

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

def train (x, y, скорость обучения, итераций = 500, порог = 0,0005):

theta = np.zeros (x.shape [1])

затраты = []

print («Начать обучение»)

для i в диапазоне (итераций):

theta = update_theta (x, y, theta, скорость_учения)

cost = cost_function (x, y, theta)

print (f ’[Шаг обучения № {i}] - Функция затрат: {cost: .4f}’)

Cost.append ({‘cost’: cost, ‘weights’: theta})

if i ›15 и abs (cost [-2] [‘ cost ’] - cost [-1] [‘ cost ’])‹ порог:

перерыв

вернуть тета, затраты

Тета, затраты = поезд (X_train, y_train, learning_rate = 0,0001)

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

def прогнозировать (x, theta):

return (sigmoid (x.dot (theta)) ›= 0,5) .astype (int)

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

def get_accuracy (x, y, theta):

y_pred = предсказать (х, тета)

return (y_pred == y) .sum () / y.shape [0]

print (f’Accuracy в обучающем наборе: {get_accuracy (X_train, y_train, theta)} ’)

print (f’Accuracy на тестовом наборе: {get_accuracy (X_test, y_test, theta)} ’)

Мы также можем сделать некоторые визуализации с помощью pyplot, чтобы посмотреть, насколько точны наши прогнозы:

plt.figure (figsize = (15,10))

plt.title («Точность модели в зависимости от шага обучения»)

plt.plot (np.arange (0, len (затраты)),

[get_accuracy (X_train, y_train, c [‘weights’]) для c затрат],

альфа = 0,7,

label = ’Train’, цвет = ’r’)

plt.plot (np.arange (0, len (затраты)),

[get_accuracy (X_test, y_test, c [‘weights’]) для c в затратах],

альфа = 0,7,

label = ’Test’, color = ’b’)

plt.xlabel («Количество итераций»)

plt.ylabel ("Точность,%")

plt.legend (loc = ’best’)

plt.grid (Истина)

plt.xticks (np.arange (0, len (затраты) +1, 40))

plt.yticks (np.arange (0,5, 1, 0,1))

plt.show ()

[Связанная статья: Советы по диагностике линейной регрессии]

Точность обучения между двумя соседними итерациями быстро меняется. Это результат использования стохастического градиентного спуска и ограничивающих значений внутри сигмоидной функции. Тем не менее, мы видим, что обучение прошло успешно, и точность на обучающем наборе составляет примерно 92%, а на обучающем наборе - почти 88%, что является довольно хорошим результатом для такого крошечного алгоритма.

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