Привет! Меня зовут Владимир Суворов, я Senior Data Scientist и core-разработчик open-source AutoML-фреймворка OutBoxML. По образованию я инженер-механик — считал прочность судовых конструкций, и именно оттуда вынес принцип, о котором эта статья.

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

Эта статья — о линейных моделях. О том, что за скромным y = w·x + b скрывается инструмент, которым инженеры полвека считали турбулентность, прочность и динамику конструкций, и которым сегодня в проде считают страховой риск — быстро, стабильно и абсолютно прозрачно. Разберём:

  • почему инженерный приём «свести сложное к линейному» работает и в ML;

  • что такое базисные функции и почему Фурье, МКЭ и сплайны — это одна и та же линейная модель;

  • как алгоритм SINDy вытаскивает уравнения физики из данных линейной регрессией;

  • и как GLM с биннингом строит гибкую кривую риска, оставаясь прозрачной для актуария — с кодом на OutBoxML и разбором реальных коэффициентов.

1. Сто простых действий против одного сложного

Начну с вопроса, который люблю задавать: что лучше — сделать сто простых операций или одну сложную, если общее время одинаково?

Я отвечаю: сто простых. Потому что сто простых действий поддаются контролю, оптимизации и дают стабильный, воспроизводимый результат. А одно сложное — это чёрный ящик, который однажды сломает продакшен так, что вы не поймёте почему.

Линейные модели — это и есть «сто простых действий». И они закрывают огромный класс задач не хуже тяжёлых «чёрных ящиков» — если опереться на инженерный подход к их настройке.

Но чтобы объяснить, откуда у меня эта убеждённость, придётся начать не с ML, а с инженерии.

2. Инженерные корни: линеаризация повсюду

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

Логика гениальна в своей простоте. Если вы заранее знаете, как выглядит функция — решение, вам не нужно вычислять её «в лоб», тратя ресурсы, как это делает нейросеть. Вы ищете лишь её параметры в известном пространстве решений. Форму вы уже знаете — осталось найти коэффициенты.

Позже я встречал этот приём снова и снова:

  • Преобразование Лапласа. На первой работе я приводил систему дифференциальных уравнений к системе линейных алгебраических (СЛАУ) и решал простыми матричными методами. Об этом была моя первая статья в Scopus Q1.

  • Метод конечных элементов (МКЭ). Сложнейший расчёт прочности сводится к линейной комбинации простых элементов. Да, матрица жёсткости огромна — но сама СЛАУ вычислительно тривиальна, мы упираемся разве что в объём оперативной памяти.

  • Линеаризация маятника. В уравнении маятника при малых углах мы заменяем sin(θ) на θ, выкидываем синус и получаем линейное уравнение, которое решается в одну строчку.

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

Добавлю ещё два примера, потому что они прямо ведут нас в ML.

Предельная нагрузка. Стандартная задача расчётчика — найти нагрузку, при которой материал уходит в пластичность (нелинейную зону). Существуют сложные модели пластичности. Но инженеру часто нужно не описать поведение внутри катастрофы, а не допустить её. Меня научили простому приёму: считать материал идеально-пластическим после предела упругости, смоделировать прямую на графике «нагрузка — деформация» и найти точку, где деформация начинает расти на порядок быстрее. Сложная физика сводится к поиску одной граничной точки линейным приближением.

Собственные частоты. Расчёт нелинейной динамики как отклика всех точек тела требует нереальных ресурсов. Но если представить отклик как линейную комбинацию собственных частот конструкции, задача рассыпается: вы раскладываете внешнюю силу по базису собственных форм и смотрите, что резонирует. Сложнейшая динамика — линейными средствами.

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

3. Мост в ML: те же три приёма

Инженерные приёмы переносятся в ML один в один.

1. Поиск границы решения вместо моделирования всего объёма (аналог пластичности). Вам часто не нужна сложная модель, идеально описывающая все данные. Если задача — бинарная классификация или отсечение фрода, линейная модель строит гиперплоскость, разделяющую классы в зоне принятия решения. Важно правильно найти саму границу, а не описывать внутренние зависимости внутри каждого класса.

2. Разложение по базисным функциям (аналог собственных частот). Линейная модель ограничена, только пока мы подаём ей сырые признаки. Но стоит спроецировать данные в новое пространство — через Kernel Trick, Fourier Features, сплайны или WoE-трансформацию — и сложная нелинейная зависимость становится линейно разделимой. Мы раскладываем сложный сигнал по понятным базисным функциям, а дальше работает стандартный линейный решатель.

Небольшая, но важная оговорка. SVM с ядром или Логистическая регрессия на признаках Фурье — они нелинейны в исходном пространстве признаков. Вся суть в том, что после проекции в новое пространство они снова линейны — и решаются как линейная задача. Именно это я и называю силой линейного подхода: нелинейность уходит в выбор базиса, а решатель остаётся простым.

3. Локальная линеаризация (аналог малых углов). Все интерпретаторы сложных моделей — тот же LIME — работают по принципу малых углов: в окрестности одной точки даже самая мощная нейросеть или бустинг ведут себя как линейная функция. Мы не линеаризуем всё — мы линеаризуем там, где смотрим.

Отсюда — главный тезис статьи, который стоит выделить:

Линеаризация не ищет точное решение во всём диапазоне. Она даёт точный ответ там, где принимается решение.

4. Базисные функции и графический анализ

Теперь — к сердцу метода. Многие при словах «линейная модель» вспоминают y = w·x + b. Но взглянём шире: под x может скрываться любая базисная функция φ(x):

y = Σ wᵢ · φᵢ(x) + b

И тогда многое встаёт на свои места:

  • Преобразование Фурье — это линейная модель по фиксированному гармоническому базису, где φₖ(x) = cos(kx), sin(kx), а веса — коэффициенты разложения.

  • Оконное преобразование — разложение по локализованным базисам.

  • МКЭ — разложение по кусочно-непрерывным функциям формы.

Смысл один: вы берёте набор функций любого типа и ищете только их веса. Единственное условие — базисные функции должны быть линейно независимы: коэффициент при одной не должен зависеть от коэффициента при другой.

Как выбрать базис? Смотреть на данные

Здесь работает самый простой и недооценённый метод — графический анализ.

Линейные модели всегда начинаются с графиков. Вы строите зависимость таргета от фактора, смотрите на форму и, имея математическую базу, узнаёте её: вот экспонента, вот ступенька. Дальше — записываете функцию в общем виде и передаёте решателю.

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

Покажу это на живом коде — но сначала два инженерных отступления, ради красоты приёма.

5. SINDy: как вытащить уравнение физики из данных линейной регрессией

Есть метод, который меня в своё время поразил: SINDy (Sparse Identification of Nonlinear Dynamics). Сегодня это один из ключевых алгоритмов в направлении AI for Science, особенно в гидрогазодинамике.

Уравнения турбулентности — крайне сложная область. Кто сталкивался с CFD-расчётами, знает: моделей турбулентности множество (k-ε, k-ω, SA и другие), и на одних и тех же граничных условиях, выбрав не ту модель, через время T вы получите совершенно разные картины течения. Инженер-расчётчик должен обладать колоссальным опытом, чтобы заранее понять физику процесса и задать правильные уравнения.

SINDy переворачивает задачу. Представьте: прозрачный канал, подкрашенный поток, съёмка на высокоскоростную камеру. Методами PIV (Particle Image Velocimetry) из видео извлекаются фактические поля скоростей. Как из этих данных восстановить сам закон течения?

  1. Вычисляем производную состояния по времени: ẋ = dx/dt.

  2. Формируем библиотеку кандидатных функций — матрицу Θ(X), куда зашиваем возможные слагаемые: линейные члены, нелинейные комбинации, градиенты, операторы Лапласа, тензоры напряжений.

  3. Получаем СЛАУ относительно неизвестных коэффициентов Ξ:

ẋ = Θ(X) · Ξ

Применяя разреженную линейную регрессию с L1-регуляризацией, SINDy обнуляет все лишние коэффициенты в Ξ и оставляет только те физические слагаемые, что реально описывают поток.

Итог поражает: даже в невероятно сложном нелинейном явлении — турбулентности — поиск самого физического уравнения сводится к прозрачной линейной задаче оптимизации. Это та же идея профессора Елисеева, доведённая до предела: мы не знаем форму заранее — так дадим модели библиотеку форм и позволим линейной регрессии выбрать нужные.

SINDy — эффектная демонстрация мощи. А теперь спустимся в продакшен, где эта же математика работает каждый день.

6. GLM в проде: биннинг, функция связи и прозрачность

Классическая актуарная задача — оценка страхового риска в КАСКО. Каждая строка датасета: факторы о человеке и машине (возраст, стаж, регион, мощность), таргет — финансовый убыток.

Функция связи

В обычной регрессии мы ищем прямую сумму Σ wᵢxᵢ. Но убыток не бывает отрицательным и сильно асимметричен — длинный правый хвост. Поэтому берут Гамма-распределение, а функцией связи — экспоненту:

Risk = exp(w₀ + w₁x₁ + ... + wₙxₙ)

или, что то же самое:

ln(Risk) = w₀ + w₁x₁ + ... + wₙxₙ

Модель линейна — но в лог-пространстве. Для бинарных факторов (пол, наличие брака) веса wᵢ подбираются идеально.

Проблема непрерывных факторов и биннинг

Сложность приходит с непрерывными нелинейными факторами. Риск 18-летнего, 30-летнего и 70-летнего водителя меняется не линейно — одним коэффициентом эту форму не поймать. И тут мы применяем ровно приём маятника: кусочно-постоянную аппроксимацию.

Разбиваем непрерывный фактор на интервалы — бины. Внутри узкого интервала считаем коэффициент постоянным. Каждый интервал становится отдельным бинарным признаком (One-Hot / dummy). На выходе — разреженная матрица, где у конкретного человека единица стоит только в его бине.

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

В коде ниже я использую WoE-кодирование (WoE_num_cat) — Weight of Evidence. Это тот же биннинг: фактор режется на интервалы, но вместо единицы каждый бин получает осмысленное значение, связанное с целевой переменной (таргетом). Суть — превращение непрерывного фактора в кусочно-постоянный — одна; WoE просто делает кодирование содержательнее.

Код: gamma-GLM на OutBoxML

Проверим всё на классике — датасете California Housing. Цена дома ведёт себя как убыток: неотрицательна, асимметрична, с правым хвостом. Та же gamma-GLM, что и в КАСКО, только без страховой специфики.

Весь пайплайн через OutBoxML:

from sklearn.datasets import fetch_california_housing
import pandas as pd, json
from outboxml.extractors import Extractor
from outboxml.automl_utils import build_default_all_models_config
from outboxml.automl_manager import AutoMLManager
from outboxml.export_results import ResultExport

class DataExtractor(Extractor):
    def extract_dataset(self):
        housing = fetch_california_housing(as_frame=True)
        return pd.concat([housing['data'], housing['target']], axis=1)

# Ключевые две строки — вся суть модели:
model_params    = {'objective': 'gamma', 'wrapper': 'glm', 'name': 'price'}
features_params = {'encoding_num': 'WoE_num_cat'}

all_models_config = build_default_all_models_config(
    data=DataExtractor().extract_dataset(),
    column_target='MedHouseVal',
    group_name='example', project='house_pricing',
    model_params=model_params,
    features_params=features_params,
)

auto_ml = AutoMLManager(
    auto_ml_config='configs/automl-house_pricing.json',
    models_config=all_models_config_name,
    extractor=DataExtractor(),
    retro=False, hp_tune=False,
)
auto_ml.update_models(send_mail=False)

ResultExport(auto_ml).plots(model_name='price', features=['MedInc'])

Обратите внимание на две строки конфига — в них вся статья:

  • 'objective': 'gamma', 'wrapper': 'glm' — гамма-распределение и GLM. Это раздел про функцию связи.

  • 'encoding_num': 'WoE_num_cat' — биннинг непрерывных факторов.

Всё остальное — обвязка. AutoMLManager(...).update_models() — тот же оркестратор, о котором я писал в статьях про OutBoxML.

Что показывают коэффициенты

А теперь — то, ради чего всё затевалось. Обученная модель отдаёт таблицу коэффициентов: по одному на каждый бин каждого фактора. Разберём три фактора; веса даны в лог-пространстве, рядом — их экспонента (во сколько раз бин множит цену относительно базового, референсного бина, чей вес принят за 0).

MedInc — медианный доход района.

MedInc
MedInc

Тринадцать бинов, и модель сама, без единой подсказки, выстроила строго монотонную кривую: от +0.10 в нижнем бине до +1.23 в верхнем. В множителях — от ×1.1 до ×3.4. Богаче район — дороже дома. Никакой чёрный ящик не даст вам такую таблицу, которую можно прямо показать бизнесу и защитить каждое число.

AveOccup — среднее число жильцов на дом.

AveOccup
AveOccup

Зеркальная картина — строгий монотонный спад до ×0.60. Выше плотность заселения — дешевле жильё. Метод одинаково прозрачно ловит и рост, и падение.

Latitude — географическая широта.

Latitude
Latitude

А вот здесь — главное. Зависимость немонотонна: на юге Калифорнии (широта ~34, Лос-Анджелес) веса положительные, дорого; севернее — резкий разворот вниз, до −0.86 (×0.42). Одним линейным коэффициентом по широте эту форму описать невозможно. Биннинг поймал его без всякой нелинейной модели. Вот она, кусочно-постоянная аппроксимация из примера с маятником — на реальных данных.

Три графика — это и есть «графический анализ» из четвёртого раздела, только построенный не до модели, а после: мы видим форму, которую модель извлекла, и можем её объяснить.

7. Где линейные модели проигрывают

Было бы нечестно не сказать, где GLM не поможет.

  • Сырой звук, изображение, текст. Там, где признаки — это пиксели или сэмплы без осмысленной структуры, ручной подбор базиса не поможет; нейросети выучивают представление сами, и это их территория.

  • Сложные взаимодействия факторов. Биннинг ловит форму по одному фактору. Когда риск определяется сложным сочетанием пяти признаков сразу, вы либо вручную конструируете взаимодействия, либо берёте бустинг, который найдёт их сам.

  • Очень высокая размерность разреженных признаков без понятной физики за ними — тот случай, когда «посмотреть на график и узнать форму» не работает, потому что графиков тысячи.

Сила линейного подхода — там, где вы понимаете природу данных и можете выбрать базис. Где не понимаете и данные бесформенны — там честнее и проще взять чёрный ящик. Инженер выбирает инструмент по задаче.

Заключение: простота — высшая степень искусства

Я не устаю удивляться масштабу задач, которые решались и решаются простыми матричными методами. Автоматическая посадка «Бурана», рекомендательные системы, расчёты прочности, гидродинамика — в основе так или иначе лежат матрицы и СЛАУ. Все эти прорывы стали возможны потому, что люди нашли правильную точку приложения рычага и свели неподъёмную задачу к понятной линейной алгебре.

Линейные методы просто красивы:

  • красивы в строгой математической постановке;

  • красивы в абсолютной интерпретируемости;

  • красивы и компактны в матричной записи: Y = X·W.

Здесь нет чёрного ящика с миллиардами параметров и нет ветвей бустинга, чью логику не объяснить бизнесу. И самое главное: именно простые матричные операции и векторные пространства лежат в основе всех современных нейросетей, LLM и MLOps-систем. Сложность создаётся комбинацией простых кирпичиков.

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


Пример с домами целиком лежит в репозитории OutBoxML — examples/housing_pricing. Об инженерном взгляде на ML я регулярно пишу в своём Telegram-канале — заходите.