Z-score — стандартизация данных для аналитика

Коротко

Z-score (стандартное отклонение от среднего) показывает, на сколько стандартных отклонений значение отличается от среднего. Формула: z = (x − μ) / σ. Z-score = 0 — значение равно среднему. Z-score = 2 — на 2σ выше среднего. Аналитику z-score нужен для поиска выбросов, стандартизации данных перед сравнением и z-теста. На собеседованиях спрашивают формулу, правило 68-95-99.7 и применение.

Формула

z = (x − μ) / σ
# Пример
x = 85       # оценка студента
mu = 70      # средняя по группе
sigma = 10   # стандартное отклонение

z = (x - mu) / sigma  # (85 - 70) / 10 = 1.5
# Студент на 1.5 стандартных отклонения выше среднего

Правило 68-95-99.7

Для нормального распределения:

  • 68% данных в пределах ±1σ (z от −1 до +1)
  • 95% данных в пределах ±2σ (z от −2 до +2)
  • 99.7% данных в пределах ±3σ (z от −3 до +3)
          99.7% (±3σ)
       ┌──────────────────┐
       │  95% (±2σ)       │
       │ ┌──────────────┐ │
       │ │ 68% (±1σ)    │ │
       │ │ ┌──────────┐ │ │
───────┼─┼─┤  μ = 0   ├─┼─┼───────
   -3σ -2σ -1σ   0   +1σ +2σ +3σ

Значение с |z| > 2 — необычное (5% случаев). |z| > 3 — экстремальное (0.3%). Это основа для определения выбросов.

Расчёт в Python

NumPy / SciPy

import numpy as np
from scipy import stats

data = [45, 50, 55, 60, 65, 70, 75, 80, 85, 90]

# Вручную
mu = np.mean(data)
sigma = np.std(data, ddof=0)  # ddof=0 для генеральной совокупности
z_scores = [(x - mu) / sigma for x in data]

# Через scipy
z_scores = stats.zscore(data)
print(z_scores)
# [-1.57, -1.22, -0.87, -0.52, -0.17, 0.17, 0.52, 0.87, 1.22, 1.57]

Pandas

import pandas as pd

df = pd.DataFrame({
    'user_id': range(1, 11),
    'revenue': [100, 200, 300, 5000, 150, 250, 180, 220, 350, 280]
})

# Z-score
df['z_score'] = (df['revenue'] - df['revenue'].mean()) / df['revenue'].std()

# Выбросы (|z| > 2)
outliers = df[df['z_score'].abs() > 2]
print(outliers)
#    user_id  revenue  z_score
# 3        4     5000     3.12  ← выброс!

Расчёт в SQL

-- Z-score в PostgreSQL
SELECT
    user_id,
    revenue,
    (revenue - AVG(revenue) OVER ()) / STDDEV(revenue) OVER () AS z_score
FROM user_revenue;

-- Найти выбросы (|z| > 2)
WITH z AS (
    SELECT
        user_id,
        revenue,
        (revenue - AVG(revenue) OVER ()) / STDDEV(revenue) OVER () AS z_score
    FROM user_revenue
)
SELECT * FROM z WHERE ABS(z_score) > 2;

Применение

1. Поиск выбросов

# Правило: |z| > 2 — потенциальный выброс, |z| > 3 — точно выброс
df['is_outlier'] = df['z_score'].abs() > 2

Альтернатива методу IQR. Z-score лучше для нормально распределённых данных, IQR — для скошенных.

2. Стандартизация перед сравнением

# Разные шкалы — нельзя сравнивать напрямую
df['salary'] = [50000, 80000, 120000]    # рубли
df['experience'] = [1, 3, 8]              # годы

# Стандартизация
for col in ['salary', 'experience']:
    df[f'{col}_z'] = (df[col] - df[col].mean()) / df[col].std()

# Теперь обе переменные в одной шкале (среднее=0, σ=1)

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

3. Аномалии в метриках

# DAU каждого дня: z-score относительно скользящего среднего
df['dau_ma30'] = df['dau'].rolling(30).mean()
df['dau_std30'] = df['dau'].rolling(30).std()
df['dau_z'] = (df['dau'] - df['dau_ma30']) / df['dau_std30']

# Алерт если |z| > 3
alerts = df[df['dau_z'].abs() > 3]

4. Z-тест

Z-score — основа z-теста для проверки гипотез:

from scipy import stats

# Средняя конверсия сайта 5%. Сегодня 60 из 1000 (6%). Значимо?
z = (0.06 - 0.05) / (0.05 * 0.95 / 1000) ** 0.5
p_value = 2 * (1 - stats.norm.cdf(abs(z)))
print(f'z = {z:.2f}, p-value = {p_value:.4f}')
# z = 1.45, p-value = 0.1471 — не значимо

Z-score vs Min-Max нормализация

Метод Формула Результат Когда
Z-score (x − μ) / σ Среднее = 0, σ = 1 Нормальные данные, выбросы
Min-Max (x − min) / (max − min) От 0 до 1 Фиксированный диапазон

Z-score сохраняет информацию о выбросах. Min-Max сжимает все данные в [0, 1] — выброс «сплющит» остальные значения.

Типичные ошибки

Z-score для ненормальных данных. Если распределение сильно скошенное, правило 68-95-99.7 не работает. Выбросы лучше искать через IQR.

ddof: 0 vs 1. np.std(data, ddof=0) — σ генеральной совокупности. np.std(data, ddof=1) — выборочное s. Для z-score обычно ddof=0, для статистических тестов — ddof=1. pandas .std() по умолчанию ddof=1.

Z-score как причина действия. Z-score > 2 — сигнал для расследования, не для автоматического действия. Всегда проверяйте контекст: может быть акция, праздник, баг в логировании.

Вопросы с собеседований

-- Что такое z-score? -- Количество стандартных отклонений от среднего. Формула: z = (x − μ) / σ. Z = 0 — среднее, z = 2 — на 2σ выше, z = −1 — на 1σ ниже.

-- Как найти выбросы через z-score? -- Вычислить z-score для каждого значения. |z| > 2 — подозрительное значение (5% случаев). |z| > 3 — вероятный выброс (0.3%). Работает для нормальных данных.

-- Что значит «правило 68-95-99.7»? -- Для нормального распределения: 68% данных в ±1σ, 95% в ±2σ, 99.7% в ±3σ от среднего.

-- Когда стандартизация обязательна? -- Перед алгоритмами, чувствительными к масштабу: k-means, PCA, KNN, регрессия с регуляризацией. Если переменные в разных шкалах (рубли vs годы) — стандартизируйте.


Потренируйтесь решать задачи — откройте тренажёр с 1500+ вопросами для подготовки к собеседованиям аналитиков.

FAQ

Z-score отрицательный — это нормально?

Да. Отрицательный z-score — значение ниже среднего. Z = −1.5 означает «на 1.5 стандартных отклонения ниже среднего». Это не «плохо» — зависит от контекста.

Z-score и p-value — как связаны?

Z-score преобразуется в p-value через таблицу нормального распределения. z = 1.96 → p = 0.05 (двусторонний). z = 2.58 → p = 0.01. Чем больше |z|, тем меньше p-value.

Как тренироваться

Z-score — базовая тема статистики для аналитика. Задачи на статистику — в тренажёре Карьерник. Больше вопросов — в разделе с примерами.