4.13 Препроцессинг признаков

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

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

В этом параграфе мы разберём, почему масштабирование так важно для алгоритмов, основанных на геометрии и градиентах. Мы изучим ключевые техники:

  • Центрирование
  • Стандартизацию
  • Масштабирование в заданный диапазон
  • Робастное скалирование, устойчивое к выбросам

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

Центрирование

Центрирование означает приведение каждого признака к нулевому среднему значению. Для матрицы это означает вычитание из каждого столбца его среднего значения:

Центрирование не изменяет форму данных, но смещает их «центр масс» в начало координат. Это упрощает геометрию задачи и устраняет ненужное смещение. Особенно важно это при наличии свободного члена в модели линейной регрессии:

Если признаки не центрированы, то поглощает как истинное смещение, так и вклад средних значений признаков, отличных от нуля (). После центрирования становится чистым сдвигом по целевой переменной, и его можно даже убрать из модели, если одновременно центрировать и .

Кроме того, центрирование упрощает многие аналитические выводы: после него ковариационная матрица становится просто , что позволяет точнее анализировать линейную зависимость признаков, их вклад в регрессию и проводить спектральный анализ (например, PCA).

Реализация в Python

Центрирование можно выполнить вручную или с помощью функции StandardScaler из библиотеки sklearn, установив with_std=False:

1import pandas as pd
2from sklearn.preprocessing import StandardScaler
3
4# Пример DataFrame
5X = pd.DataFrame({
6    'height': [160, 170, 180],
7    'weight': [55, 65, 75]
8})
9
10# Центрирование (без масштабирования)
11scaler = StandardScaler(with_mean=True, with_std=False)
12X_centered = scaler.fit_transform(X)
13
14print(pd.DataFrame(X_centered, columns=X.columns))

Стандартизация

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

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

Результирующие признаки становятся безразмерными, и все имеют одинаковое статистическое влияние. Это критически важно при использовании регуляризации. Рассмотрим, например, гребневую регрессию:

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

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

Реализация в Python

Вот классическая нормализация: вычитание среднего и деление на стандартное отклонение. Реализуется той же функцией StandardScaler, но с параметрами по умолчанию

1from sklearn.preprocessing import StandardScaler
2
3scaler = StandardScaler()
4X_scaled = scaler.fit_transform(X)
5
6print(pd.DataFrame(X_scaled, columns=X.columns))

Если используется torch, то для статической нормализации признаков (например, при передаче табличных данных в нейросеть) можно использовать torch.nn.functional.batch_norm:

1import torch
2import torch.nn.functional as F
3
4X_tensor = torch.tensor(X.values, dtype=torch.float32)
5mean = X_tensor.mean(dim=0)
6std = X_tensor.std(dim=0, unbiased=False)
7
8X_norm = F.batch_norm(X_tensor, running_mean=mean, running_var=std**2, training=False)
9
10print(X_norm)

В рамках нейросетей BatchNorm (Batch Normalization) используется не как статический препроцессинг, а как обучаемый слой, встроенный внутрь архитектуры. Его основная задача — стабилизировать и ускорить обучение за счёт нормализации активаций внутри сети. Это достигается за счёт вычитания среднего и деления на стандартное отклонение по мини-батчу:

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

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

Реализация в Python

При training=True слой использует статистики текущего батча. При training=False, он использует усреднённые оценки, накопленные в ходе обучения (так называемые running_mean и running_var), что обеспечивает стабильность на этапе инференса.

В нашем случае, когда мы просто хотим нормализовать входные признаки вручную, без обучения, мы явно передаём running_mean и running_var и устанавливаем training=False. Это полностью эквивалентно классической стандартизации признаков, как в функции StandardScaler из sklearn, но на уровне torch.Tensor:

1import torch.nn.functional as F
2
3X_norm = F.batch_norm(X_tensor, running_mean=mean, running_var=std**2, training=False)

Таким образом, мы используем BatchNorm не как обучаемый слой, а как удобный способ реализовать стандартизацию на тензорах в PyTorch без необходимости писать ручное деление.

Масштабирование

Центрирование и стандартизация стремятся устранить смещение и выровнять дисперсии признаков. Однако они не контролируют диапазон значений. В некоторых задачах важно, чтобы признаки строго укладывались в заданные интервалы, например от до или от до . Это особенно актуально в тех случаях, когда:

  • Модель чувствительна к абсолютным границам (например, нейросети с сигмоидами или тангенс-гиперболическими активациями).
  • Признаки входят в формулы расстояний (например, или -метрики в -ближайших соседях, KMeans).
  • Важны относительные масштабы между признаками (например, в визуализации или интерпретации значений).
  • Данные представлены разреженными кодами (например, one-hot), и нужно совместить их с плотными числовыми признаками.
  • Модель не устойчива к выбросам, но требуется мягкая нормализация без удаления точек (например, при подаче на автоэнкодер или на регуляризованную регрессию).

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

Этот подход называется Min-Max-нормализацией. Если необходимо изменить диапазон на , можно использовать обобщённую формулу:

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

Однако у Min-Max-нормализации есть и слабые стороны:

  • Она чувствительна к выбросам: одна аномальная точка может сжать всю шкалу признака.
  • Она не центрирует данные: среднее значение признака после нормализации зависит от формы распределения.
  • Она не приводит дисперсии к единице и не устраняет корреляцию между признаками.

Таким образом, Min-Max-нормализация — это отдельный тип препроцессинга, отличный от центрирования и стандартизации. Её следует использовать, когда модель требует контроля над диапазоном признаков, а не их распределением.

Реализация в Python

Для масштабирования признаков в Python используется класс MinMaxScaler из библиотеки sklearn.preprocessing. Вот пример, где каждый признак преобразуется в интервал :

1from sklearn.preprocessing import MinMaxScaler
2import pandas as pd
3
4# Пример исходных данных
5X = pd.DataFrame({
6    'feature_1': [12, 24, 36],
7    'feature_2': [100, 150, 300]
8})
9
10# Применяем масштабирование
11scaler = MinMaxScaler()  # По умолчанию диапазон [0, 1]
12X_scaled = scaler.fit_transform(X)
13
14# Оборачиваем обратно в DataFrame для наглядности
15X_scaled_df = pd.DataFrame(X_scaled, columns=X.columns)
16print(X_scaled_df)

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

1scaler = MinMaxScaler(feature_range=(-1, 1))

Результат сохраняет порядок и пропорции между значениями, но гарантирует, что минимум и максимум каждого признака будут строго заданы.

Робастное скалирование

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

В таких ситуациях применяется робастная стандартизация — масштабирование на основе медианы и межквартильного размаха:

где и — первый и третий квартили соответственно.
Такая нормировка нечувствительна к единичным выбросам, поскольку медиана и квартили являются робастными статистиками. Робастное скалирование особенно полезно при анализе распределений с тяжёлыми хвостами, в задаче регрессии с шумными источниками данных или в предварительном отборе признаков перед более строгими моделями (например, лассо или SVM).

Реализация в Python

Робастное скалирование используется при наличии выбросов. Вместо среднего и стандартного отклонения используется медиана и IQR (межквартильный размах):

1from sklearn.preprocessing import RobustScaler
2
3scaler = RobustScaler()
4X_robust = scaler.fit_transform(X)
5
6print(pd.DataFrame(X_robust, columns=X.columns))

Чтобы вам было проще увидеть разницу между методами препроцессинга, мы собрали информацию о них в одну табличку:

Метод

Формула

Цель применения

Центрирование

Устранение смещения, упрощение структуры матриц , интерпретация в линейных моделях

Стандартизация

(StandardScaler)

Обеспечение единичной дисперсии, улучшение сходимости, регуляризация

Масштабирование

(MinMaxScaler)

Контроль над границами значений, визуализация, совместимость с сигмоидой

Робастное скалирование

(RobustScaler)

Защита от выбросов, устойчивое масштабирование при тяжёлых хвостах

Обусловленность матрицы и её численная стабильность

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

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

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

Плохо обусловленная матрица возникает, когда признаки скоррелированы (линейно зависимы) или имеют несопоставимые масштабы. Это приводит к огромной чувствительности решения к шуму, численным ошибкам при вычислении и даже к невозможности инверсии.

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

Фактически все задачи, в которых фигурирует , включая гребневую регрессию, PCA, SVM и даже стохастический градиентный спуск (SGD), выигрывают от хорошо подготовленной матрицы признаков.

Скорость и устойчивость обучения

Наконец, качественный препроцессинг напрямую влияет на скорость сходимости итеративных методов оптимизации. Градиентный спуск работает эффективнее, когда функция потерь имеет симметричную, изотропную форму. Без нормализации градиенты будут двигаться вдоль узких вытянутых канавок (градиентные «долины»), что приводит к зигзагообразной траектории и медленному прогрессу.

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

Примером может служить логистическая регрессия с градиентным спуском. Без нормализации её обучение может занять в разы больше эпох или вовсе застрять на плато. Аналогично при использовании стохастических оптимизаторов (SGD, Adam) качество препроцессинга влияет на величину шага обучения и необходимость в адаптивных техниках.

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


Ключевые выводы о препроцессинге просты:

  • выбирайте преобразование, исходя из задачи и распределений (стандартизация по умолчанию, Min-Max — когда важен диапазон, робастные методы — при выбросах);
  • обучение любых скейлеров делайте только на обучающей части, применяя затем к валидации/тесту (исключаем утечки);
  • объединяйте препроцессинг и модель в единый пайплайн, чтобы кросс-валидация и подбор гиперпараметров учитывали весь конвейер;
  • улучшенная обусловленность и согласованные масштабы делают решения устойчивее, регуляризацию — осмысленнее, а оптимизацию — быстрее.

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

Следующий параграф — заключительный. В нём подведём итоги всей главы.



Чтобы добавить в заметки выделенный текст, нажмите Ctrl + E
Предыдущий параграф4.12. SVM и ядровой трюк
Следующий параграф4.14. Чему вы научились