Постановка ML-задачи и работа с данными

Exploratory Data Analysis: распределения и аномалии

Содержание курса

2. Форма распределения: что скрывается за числами

Описательная статистика отвечает на вопрос «где» и «насколько широко» — но не отвечает на вопрос «как именно» распределены значения. Два признака могут иметь одинаковое среднее и стандартное отклонение, но совершенно разную форму. Форма распределения характеризуется несколькими вещами:

  • Симметрия — значения равномерно расположены вокруг центра, как у нормального распределения.
  • Скошенность (skew) — хвост тянется в одну сторону. Правый хвост означает, что большинство значений небольшие, но есть редкие очень крупные.
  • Моды — количество пиков. Унимодальное распределение имеет один пик, бимодальное — два, что часто сигнализирует о двух разных группах в данных.
  • Хвосты — насколько далеко уходят крайние значения от центра. В rossmann_train.csv это хорошо видно на примере Sales. Разница между 25-м перцентилем (3 727) и 75-м (7 856) составляет около 4 100. При этом максимум — 41 551, то есть правый хвост простирается почти в 9 раз дальше верхнего квартиля. Это классическое правостороннее распределение: большинство магазинов дают выручку в диапазоне 3 700–7 900, но есть единицы с продажами на порядок выше. Посмотреть форму числом можно через skew() и kurt():

import pandas as pd

df = pd.read_csv('rossmann_train.csv')

print(df[['Sales', 'Customers']].skew())
print(df[['Sales', 'Customers']].kurt())

Значение skew > 0 означает правый хвост, skew < 0 — левый. Для Sales и Customers ожидаем заметный положительный skew, что подтверждает визуальное наблюдение из describe(). Почему форма важна на практике? Линейные модели предполагают определённые свойства остатков; если целевая переменная сильно скошена, логарифмическое преобразование Sales перед обучением может существенно улучшить качество. Кроме того, бимодальность часто указывает на смешение подгрупп — например, магазины разного типа или рабочие и выходные дни. В rossmann_train.csv дни, когда магазин закрыт (Open=0), дают Sales=0, что формирует отдельный пик в нуле и делает распределение Sales без фильтрации смесью двух режимов. Поэтому перед анализом формы распределения полезно сначала отфильтровать строки с Open=1:


df_open = df[df['Open'] == 1]
print(df_open[['Sales', 'Customers']].skew())

Это даст честную картину распределения выручки в рабочие дни, без артефакта от нулей.

Начать заново?

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

О переписке

Можно приложить до трёх фото PNG, JPEG или WebP по 5 МБ.

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

Проверка решения остаётся отдельным действием.