Именно поэтому одна и та же таблица может вести себя по-разному в зависимости от того, сделали ли мы масштабирование. Логистическая регрессия начинает сходиться стабильнее, k-NN перестает слушаться только самый крупный по масштабу признак, а PCA начинает искать направления максимальной вариации честно, а не под влиянием одной колонки с большими числами.
Удобнее всего рассматривать эту тему не как отдельный трюк в preprocessing, а как более точный разбор вопроса, когда без масштабирования признаков вообще нельзя. Тогда становится проще понять, почему одна и та же модель в разных системах координат может вести себя почти как два разных алгоритма.
Почему модель вообще чувствует масштаб признаков
Представим два признака. Первый — возраст клиента в диапазоне от 18 до 70. Второй — доход в диапазоне от 30 000 до 500 000. Если мы без подготовки отдадим их модели, то многие алгоритмы будут воспринимать изменение дохода как гораздо более сильное движение в пространстве признаков, чем изменение возраста. Причина простая: сами числа намного крупнее.
Это особенно заметно в алгоритмах, где важны расстояния, скалярные произведения или шаги оптимизации. Для k-NN, k-means, логистической регрессии, линейных моделей с регуляризацией, SVM и PCA масштаб признаков влияет непосредственно на результат. Для деревьев решений и ансамблей деревьев влияние обычно слабее, потому что они режут данные по порогам, а не по расстояниям.
Раздел математики: линейная алгебра и аналитическая геометрия.
(d(\mathbf{x}, \mathbf{x}') = \sqrt{\sum_{j=1}^{p}(x_j - x'_j)^2})
Что означает каждый символ:
(d(\mathbf{x}, \mathbf{x}')) — расстояние между двумя объектами;
(\mathbf{x}) и (\mathbf{x}') — два объекта в пространстве признаков;
(p) — число признаков;
(x_j) и (x'_j) — значения признака с номером (j) у этих объектов.
Как формула работает в ML: она лежит в основе методов, которые сравнивают объекты по близости. Если один признак измеряется в тысячах, а другой в долях, первый начинает доминировать в сумме квадратов и искажает расстояние.
Численный пример: пусть первый объект равен ((20, 40000)), а второй — ((30, 50000)). Тогда расстояние равно (\sqrt{(20-30)^2 + (40000-50000)^2}). Вклад возраста здесь равен (10^2 = 100), а вклад дохода — (10000^2 = 100000000). Модель почти не видит возраст.
Что делает стандартизация
Стандартизация отвечает на вопрос: насколько текущее значение отклоняется от среднего в единицах стандартного отклонения. Это очень удобный способ привести признаки к общему языку. После такого преобразования значения уже нельзя читать как исходные рубли, годы или километры, зато можно сравнивать их между собой.
Раздел математики: математическая статистика.
(z = \frac{x - \mu}{\sigma})
Что означает каждый символ:
(z) — стандартизированное значение;
(x) — исходное значение признака;
(\mu) — среднее значение признака по обучающей выборке;
(\sigma) — стандартное отклонение признака по обучающей выборке.
Откуда берутся параметры: сначала мы считаем (\mu) и (\sigma) только на train-части данных. Потом используем их для преобразования train, validation и test. Это важно, чтобы не допустить data leakage.
Роль формулы в алгоритме: после стандартизации признак получает среднее около нуля и разброс около единицы. Для градиентных методов это означает более ровную поверхность оптимизации и более предсказуемые шаги обновления весов.
Численный пример: пусть средний доход в train равен (\mu = 100), стандартное отклонение равно (\sigma = 20), а текущее значение дохода равно (x = 140). Тогда (z = \frac{140 - 100}{20} = \frac{40}{20} = 2). Это означает, что значение находится на два стандартных отклонения выше среднего.
Интуитивно стандартизация похожа на перевод абсолютных величин в язык относительной необычности. Не так важно, что зарплата равна 140 условных единиц. Важно, что она на две стандартные единицы выше среднего уровня по выборке.
Что делает нормализация
Нормализация обычно означает min-max scaling. Здесь идея другая: мы не измеряем отклонение от среднего, а растягиваем или сжимаем признак так, чтобы его значения оказались в фиксированном диапазоне, чаще всего от 0 до 1. Такой подход удобен, когда модели или признаки чувствительны именно к диапазону значений.
Раздел математики: линейная алгебра и численные методы.
(x' = \frac{x - x_{\mathrm{min}}}{x_{\mathrm{max}} - x_{\mathrm{min}}})
Что означает каждый символ:
(x') — нормализованное значение;
(x) — исходное значение признака;
(x_{\mathrm{min}}) — минимальное значение признака на train;
(x_{\mathrm{max}}) — максимальное значение признака на train.
Роль формулы в алгоритме: она прижимает значения к одному диапазону. Это полезно, когда нужно, чтобы все признаки были сравнимы по масштабу и не выбивались из рабочего диапазона модели.
Численный пример: пусть минимальный возраст в train равен (18), максимальный — (78), а текущий возраст равен (30). Тогда (x' = \frac{30 - x_{\mathrm{min}}}{x_{\mathrm{max}} - x_{\mathrm{min}}} = \frac{30 - 18}{78 - 18} = \frac{12}{60} = 0.2). Значит, значение занимает 20% диапазона от минимума до максимума.
Интуитивно нормализация — это перевод каждого признака в шкалу положения внутри собственного коридора. Ноль соответствует минимуму, единица — максимуму. Такой способ удобно читать, но он чувствителен к выбросам. Если в данных есть один экстремальный максимум, все остальные значения могут сжаться в узкий участок около нуля.
Именно поэтому рядом полезно держать и материал про выбросы в данных. Как только в признаке появляется редкое экстремальное значение, min-max scaling перестает быть нейтральной операцией и начинает навязывать модели очень неравномерную геометрию входа.
В чем разница между стандартизацией и нормализацией
Самая важная разница в том, на какой вопрос отвечает преобразование.
Стандартизация спрашивает: насколько далеко значение ушло от среднего по сравнению с обычным разбросом? Поэтому она хорошо подходит там, где важна статистическая сопоставимость признаков.
Нормализация спрашивает: где значение находится между минимумом и максимумом? Поэтому она удобна, когда нужен фиксированный диапазон.
Если сказать совсем коротко, то стандартизация работает через центр и разброс, а нормализация — через нижнюю и верхнюю границы.
Когда без этого действительно нельзя
Есть ситуации, где масштабирование не просто желательно, а практически обязательно.
Логистическая и линейная регрессия с регуляризацией. Если признаки живут в разных масштабах, штраф на веса начинает работать неравномерно. Модель может искусственно занижать влияние одних признаков и завышать других только из-за единиц измерения.
SVM. Здесь особенно важны расстояния и положение разделяющей поверхности. Без масштабирования один крупный признак может захватить всю геометрию разделения.
k-NN и k-means. Это прямой случай зависимости от расстояния. Если не привести признаки к сопоставимому масштабу, модель фактически выбирает соседей и кластеры по самому крупному признаку.
PCA. Метод ищет направления максимальной дисперсии. Если один признак масштабно больше остальных, именно он будет определять первые компоненты.
Нейронные сети. Здесь нормальный диапазон входов влияет на стабильность градиентов и скорость обучения. Особенно это заметно при градиентном спуске и чувствительных функциях активации.
Для этого случая особенно полезен и отдельный разбор feature scaling в нейросетях, где тема рассматривается уже не только как preprocessing табличных данных, а как часть устойчивого обучения более чувствительных архитектур.
А вот деревья решений, Random Forest и CatBoost обычно можно обучать без явного масштабирования. Они сравнивают значения с порогами внутри признака, а не строят расстояния между объектами. Это не значит, что масштабирование там всегда бесполезно, но критической необходимости обычно нет.
Геометрический смысл и связь с оптимизацией
Если смотреть на данные геометрически, то без масштабирования пространство признаков вытягивается по осям с крупными числами. Тогда облако объектов становится деформированным. Расстояния, углы и направления максимальной изменчивости искажаются.
Эта геометрическая интуиция особенно хорошо чувствуется в задачах близости и кластеризации. Например, для cosine similarity или для KMeans масштаб признаков меняет не косметику, а сам способ, которым алгоритм видит структуру пространства и различает объекты между собой.
При стандартизации оси становятся более сопоставимыми по разбросу. Облако данных перестает быть чрезмерно вытянутым в одну сторону. Для оптимизации это особенно полезно: функция потерь становится ближе к симметричной форме, а градиентный спуск делает более ровные шаги.
Если представить линии уровня функции потерь как эллипсы, то без масштабирования они часто получаются очень вытянутыми. Градиентный спуск начинает двигаться зигзагами. После стандартизации эллипсы становятся более круглыми, и траектория обучения оказывается стабильнее.
Типичная ошибка, которая ломает эксперимент
Самая частая ошибка — считать среднее, стандартное отклонение, минимум и максимум на всей выборке до разбиения на train и test. Это утечка данных. Модель получает статистическую информацию о тесте еще до обучения, и оценка качества становится слишком оптимистичной.
Правильная последовательность такая: сначала делим данные на train и test, потом fit делаем только на train, а уже затем transform применяем к train и test с теми параметрами, которые были посчитаны на train.
Python: как это выглядит на практике
В Python эта задача обычно решается через scikit-learn. Для стандартизации используют StandardScaler, для нормализации по min-max — MinMaxScaler.
import pandas as pd
# Импортируем pandas для создания небольшой таблицы с признаками.
from sklearn.model_selection import train_test_split
# Берем функцию разбиения, чтобы сначала отделить train от test.
from sklearn.preprocessing import StandardScaler, MinMaxScaler
# Импортируем два преобразователя: стандартизацию и нормализацию.
data = pd.DataFrame({
"age": [18, 22, 30, 35, 42, 50, 60, 78],
"income": [30, 45, 60, 72, 90, 120, 200, 500]
})
# Создаем таблицу с двумя признаками разного масштаба.
X_train, X_test = train_test_split(data, test_size=0.25, random_state=42)
# Сначала делим данные на train и test, чтобы не допустить утечки.
standard_scaler = StandardScaler()
# Создаем объект стандартизации.
X_train_std = standard_scaler.fit_transform(X_train)
# Считаем среднее и стандартное отклонение только на train и сразу преобразуем train.
X_test_std = standard_scaler.transform(X_test)
# Преобразуем test теми же параметрами, которые были найдены на train.
minmax_scaler = MinMaxScaler()
# Создаем объект нормализации в диапазон от 0 до 1.
X_train_mm = minmax_scaler.fit_transform(X_train)
# Находим минимум и максимум по train и преобразуем train.
X_test_mm = minmax_scaler.transform(X_test)
# Применяем те же границы диапазона к test.
print("Standardized train:")
# Печатаем заголовок для стандартизированных признаков.
print(X_train_std[:3])
# Показываем первые три стандартизированные строки train.
print("Normalized train:")
# Печатаем заголовок для нормализованных признаков.
print(X_train_mm[:3])
# Показываем первые три нормализованные строки train.Если проект строится через pipeline, то масштабирование лучше включать внутрь конвейера. Так меньше риск случайно преобразовать данные не в том порядке.
Что выбирать в реальной задаче
Если модель чувствительна к расстояниям или регуляризации, а признаки имеют разные разбросы и более или менее симметричное поведение, чаще начинают со стандартизации. Это хороший базовый выбор для линейных моделей, логистической регрессии, SVM и PCA.
Если нужен именно ограниченный диапазон, например для некоторых нейросетевых схем, визуализаций или признаков, которые должны жить в интервале от 0 до 1, логичнее использовать нормализацию.
Если в данных много выбросов, min-max scaling может стать хрупким решением, потому что максимум и минимум резко меняются из-за экстремальных значений. В такой ситуации стандартизация часто оказывается устойчивее, хотя и она не является универсальной защитой. Иногда лучше смотреть в сторону robust scaling, но это уже следующий шаг, а не стартовая настройка.
Главная мысль, которую важно унести
Стандартизация и нормализация не улучшают данные магически. Они меняют систему координат, в которой модель видит признаки. Если система координат выбрана неудачно, алгоритм начинает учиться медленнее, ошибается в расстояниях и неправильно распределяет важность признаков.
Поэтому вопрос нужно ставить не так: «что лучше — стандартизация или нормализация?», а так: «какую геометрию входного пространства ожидает моя модель и как на нее влияют масштаб, выбросы и диапазоны признаков?» Именно с этого начинается аккуратная работа с табличными данными в Data Science.
А когда признаки уже становятся векторными представлениями более сложных объектов, эта же логика продолжается в темах вроде embeddings: там вопрос масштаба, направления и расстояния тоже определяет, что именно модель считает похожестью, близостью и осмысленной структурой данных.
Kaggle notebook по теме:
https://www.kaggle.com/code/jatin2055/feature-scaling-standardization