Формулы простой и множественной линейной регрессии и их реализация с нуля
Это очень короткие формулы, как первая тема в ESL, очень базовые.
Есть много библиотек, которые могут это сделать, но как раз недавно в моей разработке мне потребовалось вычислять регрессию на GPU (что может ускорить процесс во много раз), и я решил написать блог, чтобы проверить, правильно ли отображаются формулы на сайте.
Что такое линейная регрессия
Проще говоря, это представление тенденции данных с помощью линейного уравнения.
Одна переменная: $y=mx+b$ Множество переменных: $y=m_1x_1+m_2x_2+…+b$
Можно представить, что каждая точка — это звезда одинаковой массы, а линия регрессии — это длинная палка, которая в условиях гравитации занимает положение равновесия.
Формула простой линейной регрессии с одной переменной (Linear regression)
Simple OLS regression вынесен отдельно, потому что он более наглядный и понятный:
Это ковариация, деленная на дисперсию x. Как вывести эту формулу, опустим, но вы уже должны почувствовать её очарование.
Затем b получается подстановкой найденного m:
Реализация на pyTorch
pyTorch используется для ускорения на GPU. Предположим, у нас есть данные о ценах NVDA за февраль 2018 года в переменной y:
import torch
y = torch.tensor([
225.58, 228.8 , 217.52, 230.93, 228.03, 232.63, 241.42, 246.5 ,
243.84, 249.08, 241.51, 242.15, 245.93, 246.58, 246.06, 242. ,
232.21, 236.54, 235.65, 242.16
])Затем мы генерируем x:
x = torch.arange(len(y)).float()tensor([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., 17., 18., 19.])
Код регрессии (здесь для читаемости есть повторяющиеся вычисления):
demean_x = x - x.mean()
demean_y = y - y.mean()
n_1 = x.shape[0] - 1
m = torch.sum(demean_x * demean_y / n_1) / torch.sum(demean_x ** 2 / n_1)
b = y.mean() - m * x.mean()
print(m, b)(tensor(0.7734), tensor(230.4090))
Давайте построим график, чтобы увидеть результат:
from matplotlib import pyplot as plt
plt.plot(x, y)
plt.plot(x, m * x + b)
plt.show()
Выглядит неплохо🥂.
Формула множественной линейной регрессии (Multiple Linear regression)
Суть та же, что и в простой регрессии, здесь используется матричная запись, и она ещё короче:
Одна формула решает всё, она также применима к простой линейной регрессии.
К слову, $X^TX$ встречается повсюду, есть даже хедж-фонд с названием XTX.
Реализация на pyTorch
Формула содержит много скрытой информации, а текстовое описание слишком громоздко, давайте реализуем её кодом.
Я всегда думал, что если бы к формулам в учебниках и статьях прилагался соответствующий код и результаты каждого шага, читать было бы гораздо проще, ведь для выполнения кода нужна полная информация.
Здесь для демонстрации используется линейная регрессия с двумя переменными. Чаще всего это квадратное уравнение ($y=ax^2+bx+c$), то есть аппроксимация кривой. Если это уравнение с одной переменной, почему регрессия с двумя? Потому что две переменные в регрессии означают 2 независимые переменные: $x, x^2$
Используем те же данные x, y. Сначала сгенерируем матрицу X, содержащую $x, x^2$, но обратите внимание, что здесь в первый столбец добавлена константа 1 для положительной определённости матрицы и вычисления b (на рисунке ${\hat\beta}_0$):

X = torch.stack([torch.ones(x.shape), x, x ** 2]).Ttensor([[ 1., 0., 0.], [ 1., 1., 1.], [ 1., 2., 4.], [ 1., 3., 9.], [ 1., 4., 16.], [ 1., 5., 25.], … [ 1., 15., 225.], [ 1., 16., 256.], [ 1., 17., 289.], [ 1., 18., 324.], [ 1., 19., 361.]])
Затем просто вычисляем:
b, m1, m2 = (X.T @ X).inverse() @ X.T @ y
print(b, m1, m2)(tensor(220.5210), tensor(4.0694), tensor(-0.1735))
Да, это результат. Давайте построим график:
plt.plot(x, y)
plt.plot(x, m1 * x + m2 * x**2 + b)
plt.show()
Очень хорошо👏, разве не просто? Но на самом деле за этим стоят более важные концепции, такие как множественные решения и ортогональная обработка.
Коллинеарность и проблема ортогональности
В реальном использовании редко встречаются проблемы, которые можно решить простой полиномиальной регрессией. Обычно нужно проводить регрессию по наблюдаемым значениям, а наблюдаемые значения в основном не полностью независимы, то есть ковариация между x не равна 0. Сохранение независимости между x позволяет коэффициенту отвечать только за этот x, не подвергаясь влиянию других x, что требует ортогональной корректировки.
Подробно не рассматриваем. Если вы хотите быстро решить проблему, вот грубое решение: используйте QR-разложение. Вычислив через Q, R = torch.qr(X), используйте формулу $b, m_1,…,m_n=R^{-1}Q^Ty$ для решения.
Если интересно, можете посмотреть ESL 3.2.3 Multiple Regression from Simple Univariate Regression, где множественная регрессия строится из простой одномерной.
Автор: Чжан Цзяньхао Heerozh (heerozh.com)
248520b