Не всегда необходимо запускать алгоритм оптимизации для выполнения линейной регрессии. Вы можете решить конкретное алгебраическое уравнение - нормальное уравнение - чтобы получить результаты напрямую. Хотя для больших наборов данных он даже близко не является оптимальным с точки зрения вычислений, это все же один из вариантов, о котором следует знать.
1. Введение
Линейная регрессия - один из самых важных и популярных методов прогнозирования в анализе данных. Это также один из старейших - знаменитых C.F. Гаусс в начале 19 века использовал его в астрономии для расчета орбит (подробнее).
Его цель состоит в том, чтобы подогнать лучшую линию (или гипер- / плоскость) к набору заданных точек (наблюдений) путем вычисления параметров функции регрессии, которые минимизируют конкретную функцию стоимости (ошибку), например среднеквадратичная ошибка (MSE).
Напоминаем, что ниже представлено уравнение линейной регрессии в развернутом виде.
В векторизованном виде это выглядит так:
где θ - вектор весов параметров.
Обычно поиск лучших параметров модели выполняется с помощью какого-либо алгоритма оптимизации (например, градиентного спуска) для минимизации функции стоимости. Однако можно получить значения (веса) этих параметров, решив также алгебраическое уравнение, называемое нормальным уравнением. Это определено ниже.
2. Ручные расчеты
В этой статье мы выполним линейную регрессию для очень простого случая, чтобы избежать длительных ручных вычислений. Кстати, если вы думаете, что вам нужно освежить свои навыки линейной алгебры, в Интернете есть много хороших ресурсов (например, я рекомендую YouTube series).
В этом примере есть только три точки (наблюдения) только с одной переменной (X₁). На графике они выглядят так, как показано ниже.
В этом случае уравнение линейной регрессии имеет вид:
Функции (X) и метки (y):
Обратите внимание, что мы добавляем член смещения по умолчанию, равный 1 - он будет обновляться во время наших расчетов. Не добавление этого термина приведет к неправильному решению.
Шаг 1: транспонирование матрицы X
Это относительно простая задача - строки становятся новыми столбцами.
Шаг 2. Умножение транспонированной матрицы и матрицы X
Шаг 3. Инверсия результирующей матрицы
Чтобы инвертировать простую матрицу 2x2, мы можем использовать формулу:
Таким образом, получаем:
Примечание: для больших матриц (больше 3x3) их инвертирование становится гораздо более громоздкой задачей, и обычно используется алгоритмический подход - например, исключение Гаусса. Об этом важно помнить!
Шаг 4. Умножение перевернутой матрицы на транспонированный X
Шаг 5. Окончательное умножение для получения вектора наилучших параметров.
Наконец, наши уравнения линейной регрессии принимают форму:
Нанесение этой линии на предыдущий график выглядит так, как показано ниже.
3. Реализация на Python
Те же вычисления можно реализовать в Python с помощью библиотеки Numpy, которая содержит набор функций линейной алгебры в коллекции numpy.linalg.
import numpy as np X = np.c_[[1,1,1],[1,2,3]] # defining features y = np.c_[[1,3,2]] # defining labels theta = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y) # normal equation print(theta)
Теперь мы можем определить новые функции, для которых мы хотели бы прогнозировать значения.
X_new = np.c_[[1,1,1,1],[0, 0.5,1.5,4]] # new features
Реализуя уравнение 2, мы получаем прогнозируемые значения.
y_pred = X_new.dot(theta) # making predictions print(y_pred)
4. Комментарии
Как видите, использовать обычное уравнение и реализовать его на Python довольно просто - это всего лишь одна строка кода. Так почему же он не используется повсеместно?
Проблема в его числовой сложности. Решение этого уравнения требует инвертирования матрицы, и это дорогостоящая операция - в зависимости от реализации в большой нотации O это O (n³) или немного меньше. Это означает, что масштабирование ужасно, практически означает, что когда вы удваиваете количество функций, время вычислений увеличивается в 2³ = 8 раз. Также существует некоторая вероятность, что результат шага 2 вообще не обратим, что вызовет большие проблемы. Это причины, по которым на практике такой подход необычен.
С другой стороны, этот подход рассчитывается всего за один шаг, и вам не нужно выбирать параметр скорости обучения. Кроме того, с точки зрения использования памяти этот подход является линейным O (m), что означает, что он эффективно хранит огромные наборы данных, если они помещаются только в память вашего компьютера.