Линейная регрессия как базовая модель

Формула, геометрический смысл, PHP-реализация.

Линейная регрессия – это та точка, с которой удобно начинать разговор про машинное обучение. Не потому, что она "простая", а потому, что в ней уже есть почти всё.

Здесь уже появляются ключевые элементы машинного обучения:

  • модель как функция

  • параметры

  • ошибка

  • оптимизация

  • геометрический смысл

Если понять линейную регрессию, дальше большинство моделей будут восприниматься как её усложнения.

Идея модели

Представим, что у нас есть данные: входы и правильные ответы. Например, площадь квартиры xx и её цена yy. Мы хотим научиться по входу xx предсказывать значение yy.

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

y^=wx+b\hat{y} = w \cdot x + b
circle-info

Линейная регрессия не была изобретена в одной работе. Её основы связаны с методом наименьших квадратов, который независимо разработали Карл Фридрих Гауссarrow-up-right и Адриен-Мари Лежандрarrow-up-right в начале XIX века. Изначально метод применялся в астрономии для обработки наблюдений.

Это обычное уравнение прямой на плоскости.

Здесь:

  • xx – входной признак

  • ww – коэффициент (вес)

  • bb – смещение (bias, свободный член)

  • y^\hat{y} – предсказание модели

Если признаков несколько, формула обобщается:

y^=w1x1+w2x2++wnxn+b\hat{y} = w_1 \cdot x_1 + w_2 \cdot x_2 + \dots + w_n \cdot x_n + b

Или в векторной форме, которая важна для машинного обучения:

y^=wx+b\hat{y} = \mathbf{w} \cdot \mathbf{x} + b

Здесь w\mathbf{w} и x\mathbf{x} – векторы, а точка означает скалярное произведение.

На самом деле, векторная форма – это не новая модель, а просто более удобная запись той же самой суммы.

Разберём, как именно происходит этот переход.

Развёрнутая форма

Мы уже видели, что модель можно записать так:

y^(x)=w^0+j=1pxjw^j\hat{y}(x) = \hat{w}_0 + \sum_{j=1}^{p} x_j \hat{w}_j

Это означает, что модель:

  • умножает каждый признак xjx_j на свой вес w^j\hat{w}_j

  • складывает все результаты

  • добавляет свободный член w^0\hat{w}_0

То есть это просто сумма взвешенных признаков.

Как появляется скалярное произведение

Теперь перепишем эту же формулу через векторы.

Добавим фиктивный признак, равный единице:

x=(1x1x2xp),w^=(w^0w^1w^2w^p)x = \begin{pmatrix} 1 \\ x_1 \\ x_2 \\ \vdots \\ x_p \end{pmatrix} ,\quad \hat{w} = \begin{pmatrix} \hat{w}_0 \\ \hat{w}_1 \\ \hat{w}_2 \\ \vdots \\ \hat{w}_p \end{pmatrix}

Тогда их скалярное произведение:

xw^x^\top \hat{w}

даёт:

xw^=1w^0+x1w^1++xpw^px^\top \hat{w} = 1 \cdot \hat{w}_0 + x_1 \hat{w}_1 + \dots + x_p \hat{w}_p

Это в точности та же самая сумма, что и выше.

Символ ⊤ (читается "транспонирование") означает, что вектор или матрицу переворачивают – строки становятся столбцами и наоборот. Это нужно, чтобы корректно выполнить умножение: строка на столбец даёт одно число – именно то, что нам и нужно для предсказания.

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

Связь с предыдущей записью

Поэтому записи

y^=wx+b\hat{y} = \mathbf{w} \cdot \mathbf{x} + b

и

y^(x)=xw^\hat{y}(x) = x^\top \hat{w}

– эквивалентны.

Во втором случае смещение bb просто "вшито" в вектор весов через добавленную единицу в x\mathbf{x}.

Зачем это нужно

Такая запись используется потому что она:

  • компактнее

  • естественно обобщается на матрицы (например, XwX\mathbf{w} для всего датасета)

  • удобна для вычислений и оптимизации

Коротко:

y^(x)=w^0+xjw^jxw^\hat{y}(x) = \hat{w}_0 + \sum x_j \hat{w}_j \quad \Longleftrightarrow \quad x^\top \hat{w}

Это одна и та же модель – просто записанная по-разному:

  • слева – поэлементно

  • справа – векторно

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

Ошибка и функция потерь

Модель сама по себе ничего не означает, пока мы не определили, что такое "хорошо" и "плохо" (для нас, разумеется). Для этого введём понятие ошибки.

Для одного объекта ошибка выглядит так:

e=yy^e = y - \hat{y}

Строго говоря, величина ee называется остатком (residual), а функция, которую мы оптимизируем (чуть ниже мы о ней поговорим), называется функцией потерь.

Но оптимизировать просто ошибку неудобно – как мы уже говорили в предыдущей главе положительные и отрицательные значения будут взаимно уничтожаться. Поэтому в классической линейной регрессии почти всегда используют квадратичную ошибку:

L=(yy^)2L = (y - \hat{y})^2

А для всего датасета – среднеквадратичную ошибку (MSE):

MSE=1ni=1n(yiy^i)2MSE = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2

Чем меньше значение MSE, тем точнее модель предсказывает данные. Именно эту величину мы будем минимизировать, подбирая параметры ww и bb.

Геометрический смысл

Геометрия – ключ к пониманию линейной регрессии.

Один признак – прямая

Если у нас один признак, то данные – это точки на плоскости (x,y)(x, y). Модель – это прямая. Обучение линейной регрессии означает поиск такой прямой, которая проходит "как можно ближе" к этим точкам. Близость измеряется суммой квадратов ошибок.

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

Вертикальные отрезки от точек до прямой – это и есть ошибки предсказания.

Несколько признаков – плоскость и гиперплоскость

Если признаков два, модель становится плоскостью. Если признаков больше – гиперплоскостью в многомерном пространстве.

Вектор w\mathbf{w} задаёт ориентацию этой плоскости (наклон в пространстве), а bb – её сдвиг.

Предсказание y^\hat{y} – это значение линейной функции. Геометрически его можно интерпретировать как проекцию вектора признаков xx на направление вектора весов w\mathbf{w}, с учётом смещения bb.

С этой точки зрения линейная регрессия – это задача подбора такого направления в пространстве признаков, которое лучше всего объясняет данные.

11.2 Векторы x, w и проекция на направление w

Как находятся веса

Существует два основных подхода:

  1. Аналитическое решение (через нормальные уравнения)

  2. Итеративная оптимизация (градиентный спуск)

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

Аналитическое решение

То же самое выражение для ошибки удобно записывать в матричном виде. Если собрать все объекты в матрицу признаков XX, а ответы – в вектор yy, модель можно записать как:

y^=Xw\hat{y} = X \mathbf{w}

Тогда функция потерь принимает вид:

L(w)=Xwy2L(\mathbf{w}) = \|X\mathbf{w} - y\|^2

Это та же самая сумма квадратов ошибок, только записанная компактно.

Что мы минимизируем

Раскроем норму:

L(w)=(Xwy)(Xwy)L(\mathbf{w}) = (X\mathbf{w} - y)^\top (X\mathbf{w} - y)

Берём производную

Раскрывая скобки, получаем:

L(w)=wXXw2yXw+yyL(\mathbf{w}) = \mathbf{w}^\top X^\top X \mathbf{w} - 2 y^\top X \mathbf{w} + y^\top y

Теперь продифференцируем по w\mathbf{w}:

  • wXXw2XXw\mathbf{w}^\top X^\top X \mathbf{w} \rightarrow 2 X^\top X \mathbf{w}

  • 2yXw2Xy-2 y^\top X \mathbf{w} \rightarrow -2 X^\top y

  • yy0y^\top y \rightarrow 0

Итого:

wL=2XXw2Xy\nabla_{\mathbf{w}} L = 2X^\top X \mathbf{w} - 2X^\top y

Приравниваем к нулю

Минимум достигается, когда градиент равен нулю:

2XXw2Xy=02X^\top X \mathbf{w} - 2X^\top y = 0

Сокращая на 2, получаем:

XXw=XyX^\top X \mathbf{w} = X^\top y

Это и есть нормальные уравнения.

Решение

Если матрица XXX^\top X обратима, решение записывается как:

w=(XX)1Xy\mathbf{w}^* = (X^\top X)^{-1} X^\top y

Когда решение существует

Матрица XXX^\top X должна быть обратимой. Если признаки линейно зависимы, она становится вырожденной, и:

  • обратной матрицы не существует

  • решение либо не единственное, либо не определено

Интуитивно

  • XXX^\top X отражает, как признаки связаны между собой

  • XyX^\top y – как признаки связаны с ответами

  • решение подбирает веса так, чтобы ошибка была минимальной

Коротко:

w=(XX)1Xy\mathbf{w}^* = (X^\top X)^{-1} X^\top y

– это аналитическое решение задачи линейной регрессии.

Регуляризация: Ridge и Lasso

На практике аналитическое решение не всегда ведёт себя хорошо: модель может переобучаться или становиться нестабильной.

Один из способов это исправить – добавить регуляризацию.

Ridge-регрессия (L2)

В Ridge-регрессии к функции ошибки добавляется штраф на величину весов:

L(w)=Xwy2+λw2L(\mathbf{w}) = \|X\mathbf{w} - y\|^2 + \lambda \|\mathbf{w}\|^2

Здесь второй член – это L2-норма:

w2=jwj2\|\mathbf{w}\|^2 = \sum_j w_j^2

Это означает, что большие значения весов штрафуются.

Что это даёт

  • веса становятся меньше по величине

  • модель становится более устойчивой

  • уменьшается переобучение

При этом веса уменьшаются плавно, но не обнуляются.

Решение для Ridge

В этом случае аналитическое решение немного меняется:

w=(XX+λI)1Xy\mathbf{w}^* = (X^\top X + \lambda I)^{-1} X^\top y

Добавка λI\lambda I делает матрицу устойчивой и гарантирует существование решения (то есть гарантирует, что матрица не станет вырожденной и решение просто "схлопывается").

Сравнение с Lasso

Существует другой тип регуляризации – L1:

w1=w1+w2+\|\mathbf{w}\|_1 = |w_1| + |w_2| + \dots

Он используется в Lasso-регрессии.

Главное отличие:

  • L2 (Ridge) – сглаживает веса

  • L1 (Lasso) – может занулять веса (выполняет отбор признаков)

Коротко:

  • Ridge = L2-регуляризация

  • Lasso = L1-регуляризация

Итеративная оптимизация (градиентный спуск)

Идея простая: представим, что функция потерь – это поверхность. Мы стоим в случайной точке и хотим спуститься в самую низкую.

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

Для линейной регрессии производные считаются просто. Для наглядности запишем производные для одного объекта. В случае всего датасета градиенты усредняются по всем примерам.

Lw=2x(yy^)\frac{\partial L}{\partial w} = -2 x (y - \hat{y})
Lb=2(yy^)\frac{\partial L}{\partial b} = -2 (y - \hat{y})

Эти производные показывают, как изменение параметров влияет на ошибку.

Обновление параметров выглядит так:

w:=wηLww := w - \eta \cdot \frac{\partial L}{\partial w}
b:=bηLbb := b - \eta \cdot \frac{\partial L}{\partial b}

Где η\eta – learning rate, шаг обучения.

На каждом шаге параметры немного сдвигаются в сторону уменьшения ошибки.

11.3 Поверхность ошибки и шаги градиентного спуска

Аналитическое решение vs градиентный спуск

Возникает естественный вопрос: если существует точная формула решения, зачем тогда нужен градиентный спуск?

Короткий ответ

Формула

w=(XX)1Xy\mathbf{w}^* = (X^\top X)^{-1} X^\top y

используется потому что она:

  • даёт точное решение

  • не требует подбора гиперпараметров

  • работает быстро на небольших задачах

Но она плохо масштабируется.

Когда формула – хороший выбор

Аналитическое решение удобно, если:

  • данных немного (тысячи, а не миллионы)

  • число признаков невелико

  • важно получить точный ответ без настройки

Например:

  • учебные задачи

  • статистический анализ

  • небольшие датасеты

Почему она не масштабируется

Основная проблема – обращение матрицы:

(XX)1(X^\top X)^{-1}

Это операция с вычислительной сложностью порядка: O(n3)O(n^3)

Поэтому:

  • при небольших размерах – всё работает быстро

  • при больших – становится слишком дорого

Почему её всё равно изучают

Несмотря на это, формула важна:

  • даёт точное решение (глобальный минимум)

  • помогает понять структуру задачи

  • служит ориентиром для проверки других методов

Как делают на практике

  • малые данные → аналитическое решение

  • средние → зависит от задачи

  • большие → градиентный спуск / SGD

Коротко:

  • аналитическое решение — теоретически точное

  • градиентный спуск — практический инструмент для больших данных

Почему линейная регрессия так важна

Линейная регрессия кажется простой, но она задаёт фундаментальную схему обучения моделей:

  • формирует базовый шаблон "модель" → "ошибка" → "оптимизация"

  • показывает геометрический смысл обучения

  • учит мыслить векторами и пространствами

  • напрямую связана с нейросетями (один нейрон без активации – это линейная модель)

Фактически, каждый линейный слой в нейросети – это обобщение линейной регрессии. Разница лишь в количестве слоёв и нелинейностях между ними.

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

В следующих главах мы усложним картину и поговорим о том, почему линейности часто недостаточно и как появляются нелинейные модели.

Last updated