Стандартизация (Standartization) - Лена Капаца
Стандартизация (Standartization) by Лена Капаца Jan. 29, 2021 Статистика

Стандартизация (Standartization, Z-score Normalization) – техника преобразования значений признака (Feature), адаптирующая признаки с разными диапазонами значений к Моделям (Model) Машинного обучения (ML), использующих дистанцию для прогнозирования. Эта разновидность нормализации с использованием Стандартизированной оценки (Z-Score) преобразует значения таким образом, что из каждого Наблюдения (Observation) каждого Признака вычитается Среднее значение (Mean) и результат делится на Стандартное отклонение (Standard Deviation) этого признака. Как правило, каждый стандартизованный элемент признака вычисляется следующим образом:

$$x_{i,станд.} = \frac{x_i - μ}{σ}, где$$
$$x_{i,станд.}\space{–}\space{стандартизованный}\space{элемент}\space{признака,}$$
$$x_i\space{–}\space{исходный}\space{элемент,}$$
$$μ\space{–}\space{среднее}\space{арифметическое,}$$
$$σ\space{–}\space{стандартное}\space{отклонение}$$

Такое преобразование необходимо, поскольку признаки датасета могут иметь большие различия между своими диапазонами, и для моделей Машинного обучения, основанных на вычислении дистанции между точками на графике как основу прогнозирования: Метод k-ближайших соседей (kNN), Метод опорных векторов (SVM), Дерево решений (Decision Tree) и проч., это спровоцирует искаженное восприятие данных.

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

Нормализовать или стандартизировать?

"Нормализация (Normalization) или стандартизация?" – извечный вопрос среди новичков. Первую удобно использовать, когда мы знаем, что распределение данных не соответствует Гауссову, то есть нормальному:

Нормальное распределение возврата инвестиций S&P 500

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

Даже если у вас есть Выбросы (Outlier) в ваших данных, стандартизация не повлияет на них. Однако выбор между типами преобразований будет зависеть от бизнес-задачи и выбранного алгоритма Машинного обучения. Не существует жесткого правила, которое подскажет, когда нормализовать или стандартизировать данные. Вы всегда можете начать с подгонки моделей к необработанным, нормализованным и стандартизованным данным и сравнить их производительность для достижения наилучших результатов.

Хорошая практика – это стандартизировать Тренировочные (Train Data) и Тестовые данные (Test Data), причем только Предикторы (Predictor Variable). Целевая переменная (Target Variable) остается в неизменном виде, и это позволяет избежать утечки данных в процессе тестирования модели.

Стандартизация и Scikit-learn

Стандартизацию можно выполнить с помощью функции Sklearn.preprocessing.StandardScaler(). Мы будем использовать упрощенный пример @discdiver (статья на английском). Для начала импортируем библиотеки:

import matplotlib # Для графиков
import matplotlib.pyplot as plt

import numpy as np 
import pandas as pd # Для датафреймов
import seaborn as sns # Для графиков

import sklearn # Для стандартизации
from sklearn import preprocessing

Сгенерируем датасет из случайных чисел

df = pd.DataFrame({ 
    # Экспоненциальное распределение, 10 – "резкость" экспоненты, 1000 – размер
    'exponential': np.random.exponential(10, 1000), 

    # Нормальное распределение, 10 – среднее значение р., 2 – стандартное отклонение, 1000 – количество сэмплов
    'normal_p': np.random.normal(10, 2, 1000) 
})

Зададим параметры холста Seaborn, название и визуализируем кривые распределения:

fig, (ax1) = plt.subplots(ncols = 1, figsize = (10, 8))
ax1.set_title('Оригинальные распределения')

# kdeplot() (KDE – оценка плотности ядра) – специальный метод для графиков распределений
sns.kdeplot(df['exponential'], ax = ax1)
sns.kdeplot(df['normal_p'], ax = ax1)

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

# Инициализируем стандартизатор
s_scaler = preprocessing.StandardScaler()

# Копируем исходный датасет
df_s = s_scaler.fit_transform(df)

# Копируем названия столбцов, которые теряются при использовании fit_transform()
col_names = list(df.columns)

# Преобразуем промежуточный датасет в полноценный датафрейм для визуализации
df_s = pd.DataFrame(df_s, columns = col_names)

# Расположим распределения на одном полотне
fig, (ax1) = plt.subplots(ncols = 1, figsize = (10, 8))

# Зададим название графика
ax1.set_title('После стандартизации')

sns.kdeplot(df_s['exponential'], ax = ax1)
sns.kdeplot(df_s['normal_p'], ax = ax1)

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

Ноутбук, не требующий дополнительной настройки на момент написания статьи, можно скачать здесь.

Фото: @jasonortego

© Лена Капаца. Все права защищены.