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

Давайте быстро введем наши обозначения. Пусть X будет (n, m)-матрицей, представляющей входные данные, а y будет (n, 1)-матрица, представляющая целевые данные, где m — количество объектов на точку данных, а n — количество точек данных. В отличие от ранее, когда в качестве параметров модели у нас были w и b, вместо этого мы объединим их в один параметр, обозначенный θ, который будет (m+1, 1)-матрица. Параметр θ представляет собой транспонирование [b, w], т. е. b накладывается на w. Эти два подхода эквивалентны, но использование θ позволяет провести более элегантное и компактное обсуждение. Наконец, поскольку мы используем θ, нам также потребуется изменить X на (n, m+1)-матрицу, что и делается путем введения строки из единиц в качестве первой строки исходной матрицы X.

Модель линейной регрессии с использованием приведенных выше обозначений задается следующим образом:

В качестве быстрой проверки работоспособности h выводит требуемую (n, 1)-матрицу. Цель линейной регрессии состоит в том, чтобы минимизировать следующую функцию стоимости:

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

Используя матричное исчисление, градиент функции стоимости J по отношению к θ определяется следующим образом:

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

Если мы вспомним из исчисления, экстремумы J можно найти с помощью теста первой производной, установив градиент равным 0 и найдя θ:

Подставив значения X и y в приведенное выше выражение, мы получим минимальное значение θ для нашей задачи линейной регрессии. Затем мы можем использовать θ для прогнозирования выхода новых входных данных, используя модель h(x) =θ∙x, где x(m+1, 1)-матрица.

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

# Import libraries
import numpy as np
import matplotlib.pyplot as plt

# Set seed for reproducibility
np.random.seed(42)

# Set the number of data points
n = 10

# Generate data of the form y = m(x + e) + b
noise = np.random.rand(n)
bias = np.random.randint(-10, 10)
slope = np.random.randint(0, 5)

# Print the slope, bias, and noise used to generate data
print(f'slope: {slope}, bias: {bias}')
# >> slope: 3, bias: -9

x = np.arange(n)
y = slope * (x + noise) + bias

# Plot the data
plt.scatter(x, y)
plt.title('Randomly generated linear regression task')
plt.xlabel('x')
plt.ylabel('y')
plt.show()

# Model function
def model(X, theta):
    return np.dot(X, theta)

# Mean-squared error loss function
def loss(hx, y):
    return np.sum((hx - y) ** 2) / (2 * n)

# Add bias column to X
X = np.concatenate([np.ones((n, 1)), x.reshape((n, 1))], axis=1)

# Solve for theta
theta = np.linalg.inv(X.T @ X) @ (X.T @ y)

# The optimal theta parameters found
print(f'Optimal theta paramter: {theta}')
# >> Optimal theta paramter: [-7.4071701   2.99279562]

# The final loss
print(f'Final loss: {loss(model(X, theta), y)}')
# >> Final loss: 0.4038588210616574

plt.scatter(x, y)
plt.plot(x, model(X, theta))
plt.title('Plot of linear regression line given parameters theta.')
plt.xlabel('x')
plt.ylabel('y')
plt.show()

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

Несколько заключительных замечаний перед окончанием. Метод нормальных уравнений — это особый подход, уникальный для линейной регрессии. Большинство, если не все, другие модели машинного обучения, которые мы обсудим в будущем, не допускают такого красивого аналитического решения в закрытой форме. С другой стороны, градиентный спуск — это метод оптимизации общего назначения, который будет использоваться с большинством других моделей машинного обучения. По этой причине мы решили сначала описать метод градиентного спуска. Кроме того, даже если мы можем использовать нормальные уравнения для линейной регрессии, мы не всегда можем этого захотеть. Это связано с тем, что для решения θ требуется взять обратную матрицу, которая в худшем случае имеет кубическое время выполнения. Следовательно, если X является большой матрицей, использование итеративного подхода с градиентным спуском может асимптотически выполняться быстрее. На самом деле, большинство интересующих задач имеют большую матрицу плана X, поэтому полезность нормальных уравнений быстро уменьшается. Наконец, поскольку решение для θ требует вычисления обратной величины XX, мы должны убедиться, что матрица обратима, что гарантируется, если есть не являются линейно зависимыми функциями в X. Даже если XX необратим, можно правильно найти θ, используя обратную функцию Мура-Пенроуза, но это техническая деталь. выходит за рамки этой статьи.

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

Вы можете найти код для этого поста и других моих проектов на github.com/tarickali.