Масштабирование: StandardScaler, MinMaxScaler

Масштабирование: StandardScaler, MinMaxScaler Scikit-learn

Привет! Ты загрузил данные, изучил их, построил графики… Но вот проблема: один признак измеряется в тысячах, а другой — в единицах. Алгоритмы машинного обучения могут принять большие числа за более важные признаки. Как это исправить? С помощью масштабирования!

В этой статье мы разберём:

  • Зачем нужно масштабирование
  • StandardScaler — стандартизация (среднее = 0, дисперсия = 1)
  • MinMaxScaler — нормализация в диапазон [0, 1]
  • Как применять, чтобы не было утечки данных
  • Какой метод когда выбрать

Что нужно знать перед началом

Для этого урока тебе понадобится:

  • Установленный scikit-learn (pip install scikit-learn)
  • Базовое понимание машинного обучения
  • Знание, что такое признаки (X) и целевая переменная (y)

Совет: Масштабирование — обязательный шаг для многих алгоритмов. Не пропускай его!

Основная часть

Зачем масштабировать данные?

Представь, что у тебя два признака: возраст (от 0 до 100) и зарплата (от 0 до 1 000 000). Алгоритмы, основанные на расстоянии (KNN, SVM), будут считать, что зарплата в 10 000 раз важнее возраста, просто потому что числа больше. Это неправильно!

Какие алгоритмы требуют масштабирования:

  • K-ближайших соседей (KNN)
  • Метод опорных векторов (SVM)
  • Линейная и логистическая регрессия с регуляризацией
  • Нейронные сети
  • PCA и другие методы снижения размерности

Какие алгоритмы НЕ требуют масштабирования:

  • Деревья решений
  • Случайный лес
  • Градиентный бустинг

Совет: Для алгоритмов на основе расстояний масштабирование критически важно. Для деревьев — необязательно, но иногда помогает ускорить обучение.

StandardScaler — стандартизация

StandardScaler преобразует данные так, чтобы среднее значение стало 0, а стандартное отклонение — 1.

Формула:

z = (x — mean) / std

Что происходит:

  • Каждое значение центрируется (вычитается среднее)
  • Масштабируется (делится на стандартное отклонение)
  • Результат: среднее = 0, дисперсия = 1
from sklearn.preprocessing import StandardScaler
import numpy as np

# Пример данных
X = np.array([[1, 2], [3, 4], [5, 6]])

# Создаём scaler
scaler = StandardScaler()

# Обучаем и преобразуем
X_scaled = scaler.fit_transform(X)

print("До масштабирования:")
print(X)
print("\nПосле StandardScaler:")
print(X_scaled)
print(f"\nСреднее: {X_scaled.mean(axis=0)}")
print(f"Стандартное отклонение: {X_scaled.std(axis=0)}")

Результат:

До масштабирования:
[[1 2]
 [3 4]
 [5 6]]

После StandardScaler:
[[-1.22474487 -1.22474487]
 [ 0.          0.        ]
 [ 1.22474487  1.22474487]]

Среднее: [0. 0.]
Стандартное отклонение: [1. 1.]

Совет: StandardScaler подходит для алгоритмов, которые предполагают нормальное распределение данных (линейная регрессия, логистическая регрессия, SVM, PCA).

MinMaxScaler — нормализация

MinMaxScaler сжимает данные в заданный диапазон (по умолчанию от 0 до 1).

Формула:

x_scaled = (x — min) / (max — min)

Что происходит:

  • Находится минимум и максимум
  • Все значения линейно преобразуются в диапазон [0, 1]
  • Сохраняется относительный порядок значений
from sklearn.preprocessing import MinMaxScaler
import numpy as np

# Пример данных
X = np.array([[1, 2], [3, 4], [5, 6]])

# Создаём scaler
scaler = MinMaxScaler()

# Обучаем и преобразуем
X_scaled = scaler.fit_transform(X)

print("До масштабирования:")
print(X)
print("\nПосле MinMaxScaler:")
print(X_scaled)
print(f"\nМинимум: {X_scaled.min(axis=0)}")
print(f"Максимум: {X_scaled.max(axis=0)}")

Результат:

До масштабирования:
[[1 2]
 [3 4]
 [5 6]]

После MinMaxScaler:
[[0.  0. ]
 [0.5 0.5]
 [1.  1. ]]

Минимум: [0. 0.]
Максимум: [1. 1.]

Совет: MinMaxScaler хорошо работает, когда нужно сохранить нулевые значения или когда данные имеют известные границы. Идеален для нейросетей и KNN.

Сравнение методов

ХарактеристикаStandardScalerMinMaxScaler
Формула(x — mean) / std(x — min) / (max — min)
ДиапазонНеограничен[0, 1] (по умолчанию)
Среднее0Зависит от данных
Стандартное отклонение1Зависит от данных
Чувствительность к выбросамВысокая Высокая 
Когда использоватьЛинейные модели, SVM, PCAНейросети, KNN, алгоритмы с градиентным спуском

Совет: Если в данных есть выбросы, рассмотри RobustScaler — он использует медиану и квартили.

Как правильно применять: fit() и transform()

Золотое правило масштабирования:

Учимся на тренировочной выборке, применяем и к тренировочной, и к тестовой .

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_iris

# Загружаем данные
iris = load_iris()
X, y = iris.data, iris.target

# Разделяем на train/test
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42
)

# 1. Создаём scaler
scaler = StandardScaler()

# 2. Обучаем на ТРЕНИРОВОЧНЫХ данных (fit)
scaler.fit(X_train)

# 3. Применяем к тренировочным (transform)
X_train_scaled = scaler.transform(X_train)

# 4. Применяем к тестовым (transform) — используем те же параметры!
X_test_scaled = scaler.transform(X_test)

print("Среднее на train:", X_train_scaled.mean(axis=0))
print("Среднее на test:", X_test_scaled.mean(axis=0))

Совет: Никогда не используй fit_transform() на всём наборе данных сразу! Это называется утечка данных (data leakage) и даст завышенные результаты .

Работа с Pipeline

Для удобства можно объединить масштабирование и обучение в один конвейер:

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

# Данные
iris = load_iris()
X_train, X_test, y_train, y_test = train_test_split(
    iris.data, iris.target, test_size=0.3, random_state=42
)

# Создаём Pipeline
pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('classifier', LogisticRegression(max_iter=1000))
])

# Обучаем (scale и модель автоматически)
pipeline.fit(X_train, y_train)

# Предсказываем (scale применяется автоматически)
accuracy = pipeline.score(X_test, y_test)
print(f"Точность: {accuracy:.2%}")

Совет: Pipeline гарантирует, что масштабирование будет применяться корректно при кросс-валидации.

Пример с Iris: сравнение методов

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score

# Загружаем данные
iris = load_iris()
X, y = iris.data, iris.target

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

def evaluate_scaler(scaler, name):
    # Масштабируем
    scaler.fit(X_train)
    X_train_scaled = scaler.transform(X_train)
    X_test_scaled = scaler.transform(X_test)
    
    # Обучаем KNN
    model = KNeighborsClassifier(n_neighbors=5)
    model.fit(X_train_scaled, y_train)
    
    # Оцениваем
    y_pred = model.predict(X_test_scaled)
    acc = accuracy_score(y_test, y_pred)
    print(f"{name}: {acc:.2%}")

# Без масштабирования
model = KNeighborsClassifier(n_neighbors=5)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print(f"Без масштабирования: {accuracy_score(y_test, y_pred):.2%}")

# С масштабированием
evaluate_scaler(StandardScaler(), "StandardScaler")
evaluate_scaler(MinMaxScaler(), "MinMaxScaler")

Результат (примерный):

Без масштабирования: 93.33%
StandardScaler: 96.67%
MinMaxScaler: 96.67%

Совет: В датасете Iris масштабирование даёт небольшое улучшение. На данных с разными масштабами разница может быть огромной!

Задачи для закрепления

Задача 1. Объясни, зачем нужно масштабирование признаков.

Задача 2. В чём разница между StandardScaler и MinMaxScaler?

Задача 3. Почему нельзя использовать fit_transform() на всём наборе данных сразу?

Задача 4. Какой метод масштабирования лучше выбрать для KNN?

Задача 5. Создай Pipeline с StandardScaler и логистической регрессией.

Ответы:

Задача 1.

Масштабирование нужно, чтобы признаки с большими числовыми значениями не доминировали над признаками с маленькими значениями. Алгоритмы, основанные на расстоянии (KNN, SVM), чувствительны к этому.

Задача 2.

  • StandardScaler: делает среднее = 0, дисперсию = 1. Не ограничивает диапазон.
  • MinMaxScaler: сжимает данные в диапазон [0, 1].

Задача 3.

fit_transform() на всём наборе приводит к утечке данных — параметры масштабирования (mean, std, min, max) вычисляются с учётом тестовых данных, что даёт завышенную оценку качества.

Задача 4.

Для KNN подходят оба метода. MinMaxScaler часто работает лучше, потому что KNN чувствителен к относительным расстояниям, и диапазон [0, 1] даёт более понятные расстояния.

Задача 5.

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression

pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('classifier', LogisticRegression())
])
pipeline.fit(X_train, y_train)

Нюансы и подводные камни

StandardScaler чувствителен к выбросам

Выбросы сильно влияют на среднее и стандартное отклонение . Если в данных есть выбросы, рассмотри RobustScaler.

MinMaxScaler чувствителен к выбросам

Выбросы сдвигают min и max, и основная часть данных может оказаться сжатой в узкий диапазон.

fit на train, transform на test

Это не просто рекомендация, а правило. Нарушение приведёт к неправильной оценке модели.

Частые ошибки и как их избежать

Ошибка 1: fit_transform на всём наборе

# Утечка данных
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# Правильно
scaler.fit(X_train)
X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)

Ошибка 2: Забыл масштабировать категориальные признаки

Масштабируй только числовые признаки. Категориальные кодируй отдельно (OneHotEncoder).

Ошибка 3: Не сохранил scaler после обучения

Если ты сохраняешь модель, сохраняй и scaler, чтобы применять его к новым данным:

import joblib

joblib.dump(scaler, 'scaler.pkl')
joblib.dump(model, 'model.pkl')

Шпаргалка

Что нужноКак пишется
Импорт StandardScalerfrom sklearn.preprocessing import StandardScaler
Импорт MinMaxScalerfrom sklearn.preprocessing import MinMaxScaler
Создать scalerscaler = StandardScaler()
Обучитьscaler.fit(X_train)
ПреобразоватьX_scaled = scaler.transform(X)
Обучить и преобразоватьX_scaled = scaler.fit_transform(X)
PipelinePipeline([('scaler', StandardScaler()), ('model', LogisticRegression())])

Заключение

Сегодня мы узнали:

  • Зачем масштабировать данные перед обучением
  • StandardScaler — стандартизация (среднее 0, дисперсия 1)
  • MinMaxScaler — нормализация в [0, 1]
  • Правило: fit на train, transform на test
  • Pipeline для автоматизации

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

СценарийРекомендация
Линейная регрессия, SVM, PCAStandardScaler
Нейросети, KNNMinMaxScaler
Есть выбросыRobustScaler
Нужно сохранить нольMinMaxScaler

КВИЗ

Что дальше?

Оцените статью
IMI-DS - PYTHON LERNEN
Содержание
Оглавление ×