0Pricing
Pandas & NumPy Academy · Урок

Очистка данных и конструирование признаков

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

«Очистка данных и конструирование признаков» — бесплатный урок Pandas & NumPy Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Pandas & NumPy Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Pandas & NumPy Academy содержит 4 уроков всего.

Загрузка проверенного набора данных

Продолжая итоговый проект, загрузите контрольную версию очищенного набора данных в формате Parquet, сохранённую на предыдущем этапе. Это отделяет этап очистки от загрузки: Вы сможете изменять логику очистки, не запуская повторно медленные операции объединения и разбора данных. Прочитайте Parquet-файл clean_orders и убедитесь, что количество строк и типы данных соответствуют ожиданиям из итогового отчёта о проверке. Файл Parquet сохраняет все типы данных, включая категориальные столбцы, поэтому повторное приведение типов не требуется.

import pandas as pd

# Load from checkpoint
df = pd.read_parquet('output/clean_orders.parquet')
print(f'Loaded: {df.shape}')
print(df.dtypes)
print(f'Date range: {df["order_date"].min().date()} to {df["order_date"].max().date()}')

Применение расширенного списка очистки

Загрузив объединённый набор данных, примените расширенный список очистки: удалите полные и частичные дубликаты по order_id, ограничьте выбросы в unit_price с помощью метода межквартильного размаха, приведите непоследовательные значения category к единому виду (например, 'Electronics', 'electronics' и 'ELECTRONIC') и проверьте, что quantity × unit_price всегда положительно для обычных заказов. Каждый этап реализуется как функция, принимающая и возвращающая DataFrame, что делает конвейер пригодным для тестирования и обратимых преобразований.

import pandas as pd
import numpy as np

def remove_duplicates(df):
    n_before = len(df)
    df = df.drop_duplicates(subset=['order_id'], keep='first')
    print(f'Duplicates removed: {n_before - len(df)}')
    return df

def standardise_categories(df):
    df['category'] = (df['category']
                      .astype(str)
                      .str.strip()
                      .str.title())
    return df

def cap_price_outliers(df):
    q1, q3 = df['unit_price'].quantile([0.25, 0.75])
    iqr = q3 - q1
    upper = q3 + 3 * iqr
    df['unit_price'] = df['unit_price'].clip(upper=upper)
    return df

df = remove_duplicates(df)
df = standardise_categories(df)
df = cap_price_outliers(df)
print('Cleaning complete.')

Создание признаков даты

Извлеките временные признаки из даты заказа с помощью средства доступа .dt. Создайте столбцы year, month, quarter, day_of_week и week_of_year. Эти признаки используются в анализе с помощью groupby (например, при расчёте ежемесячной выручки), фильтрации по времени (только третий квартал) и визуализациях. Также создайте строковый столбец year_month (например, '2024-06') как понятную пользователю метку периода для осей графиков.

import pandas as pd

df['year'] = df['order_date'].dt.year
df['month'] = df['order_date'].dt.month
df['quarter'] = df['order_date'].dt.quarter
df['day_of_week'] = df['order_date'].dt.dayofweek  # 0=Monday
df['week'] = df['order_date'].dt.isocalendar().week.astype('int32')
df['year_month'] = df['order_date'].dt.to_period('M').astype(str)

print('Date features created:')
print(df[['order_date', 'year', 'month', 'quarter', 'year_month']].head())

Расчёт выручки по позициям заказа

Самый фундаментальный показатель в наборе данных о продажах — выручка по позиции заказа: revenue = quantity × unit_price. Создайте для неё новый столбец. Если доступны данные о себестоимости, также создайте столбец gross_margin: margin = (price - cost) / price. Эти производные столбцы служат основой для всех KPI, связанных с выручкой. Всегда используйте векторизованные операции над столбцами, а не циклы: одно присваивание для всего столбца на порядки быстрее последовательной обработки строк.

import pandas as pd

# Line-item revenue
df['revenue'] = (df['quantity'] * df['unit_price']).astype('float32')

# Gross margin (if unit_cost column exists)
if 'unit_cost' in df.columns:
    df['gross_margin'] = (df['unit_price'] - df['unit_cost']) / df['unit_price']

# Discount flag: orders with more than 20% off list price
if 'list_price' in df.columns:
    df['is_discounted'] = df['unit_price'] < df['list_price'] * 0.8

print('Revenue stats:')
print(df['revenue'].describe().round(2))

Назначение клиентов по когортам

Когорта — это группа клиентов, объединённых общим признаком, обычно периодом, когда они впервые совершили покупку. Назначьте каждого клиента в его когорту привлечения, найдя дату его первого заказа. Используйте groupby('customer_id')['order_date'].min(), чтобы вычислить дату первого заказа для каждого клиента, а затем создайте столбец cohort_month, преобразовав эту дату в период «год-месяц». Эта метка когорты станет основой матрицы удержания в следующем уроке.

import pandas as pd

# First purchase date per customer
first_purchase = (
    df.groupby('customer_id')['order_date']
    .min()
    .dt.to_period('M')
    .astype(str)
    .rename('cohort_month')
)

# Merge back onto orders
df = df.merge(first_purchase, on='customer_id', how='left')
print('Cohort distribution (top 5):')
print(df['cohort_month'].value_counts().head())
print(f'Distinct cohorts: {df["cohort_month"].nunique()}')

Признаки пожизненной ценности клиента

Вычислите сводные признаки на уровне клиента: общее число заказов, общую выручку, среднюю стоимость заказа, количество дней с момента первой и последней покупки, а также число различных приобретённых категорий. Объедините эти данные с основным DataFrame в виде обогащающих столбцов на уровне клиента. Эти признаки используются для сегментации (например, клиентов с высокой и низкой ценностью), а также подаются на вход моделям машинного обучения, прогнозирующим отток или вероятность дополнительных покупок.

import pandas as pd

customer_stats = df.groupby('customer_id').agg(
    total_orders=('order_id', 'nunique'),
    total_revenue=('revenue', 'sum'),
    avg_order_value=('revenue', 'mean'),
    categories_purchased=('category', 'nunique'),
    first_order=('order_date', 'min'),
    last_order=('order_date', 'max')
).reset_index()

customer_stats['days_as_customer'] = (
    (customer_stats['last_order'] - customer_stats['first_order'])
    .dt.days
)

print(customer_stats.describe().round(2))

Проверка схемы с помощью утверждений

После создания признаков выполните утверждения для проверки схемы, чтобы убедиться, что данные соответствуют ожиданиям, прежде чем передавать их на этап анализа. Проверьте наличие всех ожидаемых столбцов, неотрицательность выручки для обычных заказов, отсутствие пропусков в cohort_month и соответствие year_month году анализа. Эти утверждения работают как контракт: если хотя бы одно из них не выполнено, pipeline немедленно останавливается с понятным сообщением об ошибке, вместо того чтобы незаметно выдавать неверные результаты.

import pandas as pd

def validate_clean_df(df):
    required_cols = ['order_id', 'customer_id', 'revenue', 'year_month',
                     'cohort_month', 'category', 'region', 'order_date']
    missing = [c for c in required_cols if c not in df.columns]
    assert not missing, f'Missing columns: {missing}'

    assert (df['revenue'] >= 0).all(), 'Negative revenue found'
    assert df['cohort_month'].notna().all(), 'Null cohort_month values'
    assert df['order_date'].notna().all(), 'Null order dates'
    print(f'Validation passed: {len(df):,} rows, {len(df.columns)} columns')

validate_clean_df(df)

Обработка редких категорий

В реальных наборах данных некоторые категории или регионы встречаются всего несколько раз — слишком редко для содержательного анализа. Заменяйте редкие значения на «Other», чтобы диаграммы не были перегружены десятками категорий, представленных одним заказом. Практический порог: значения, встречающиеся менее чем в 0,5% строк, объединяются. Это важно и для машинного обучения: one-hot-кодирование 200 редких категорий расходует память и добавляет шум.

import pandas as pd

def collapse_rare_values(df, col, min_pct=0.005):
    threshold = len(df) * min_pct
    counts = df[col].value_counts()
    rare = counts[counts < threshold].index
    n_rare = len(rare)
    df[col] = df[col].apply(lambda x: 'Other' if x in rare else x)
    print(f'{col}: collapsed {n_rare} rare values into "Other"')
    return df

df = collapse_rare_values(df, 'category', min_pct=0.005)
df = collapse_rare_values(df, 'region', min_pct=0.005)
print('Category distribution after collapsing:')
print(df['category'].value_counts())

Сохранение набора данных после создания признаков

Сохраните полностью очищенный DataFrame с созданными признаками в качестве контрольной точки в формате Parquet. Это набор данных, готовый к анализу — результат всех этапов загрузки, очистки и создания признаков. Последующие этапы pipeline (вычисление KPI, визуализация, подготовка отчёта) считывают данные из этой контрольной точки. Она также служит результатом работы: ею можно поделиться с членами команды или загрузить в озеро данных, чтобы другие могли выполнять к ней запросы с помощью SQL или Pandas.

import pandas as pd

# Convert category columns back to Categorical for memory efficiency
for col in ['category', 'region', 'acquisition_channel']:
    if col in df.columns:
        df[col] = df[col].astype('category')

# Save analysis-ready dataset
df.to_parquet('output/analysis_ready.parquet', index=False)

# Also save customer stats for segmentation
customer_stats.to_parquet('output/customer_stats.parquet', index=False)

print(f'Analysis-ready dataset: {df.shape}')
print(f'Memory usage: {df.memory_usage(deep=True).sum()/1e6:.1f} MB')

Итоги создания признаков

Хорошее создание признаков сочетает добавление прогностического сигнала с сохранением понятности и возможности тестирования pipeline. Признаки, созданные на этом этапе, — выручка, составляющие даты, cohort_month, статистики клиентов и объединённые категории — определялись целями анализа, заданными при настройке проекта. Не поддавайтесь искушению создавать десятки признаков без конкретной цели. Для каждого признака спросите себя: будет ли он использован хотя бы в одном KPI или элементе визуализации? Если нет, отложите его создание. Набор данных, готовый к анализу, должен быть компактным и целенаправленным.

import pandas as pd

# Summary of engineered features
df = pd.read_parquet('output/analysis_ready.parquet')

original_cols = ['order_id', 'customer_id', 'order_date', 'quantity', 'unit_price']
engineered_cols = [c for c in df.columns if c not in original_cols]

print('Original columns:', original_cols)
print('Engineered features:', engineered_cols)
print(f'Total columns: {len(df.columns)}')
print(f'Total rows: {len(df):,}')

Документирование решений в коде

Для каждого неочевидного решения при очистке или создании признаков добавляйте комментарий с объяснением причины. Вы в будущем или другой член команды не вспомните, почему множитель IQR был установлен равным 3, а не 1,5, или почему для порога редкой категории выбрано значение 0,5%. Встроенные комментарии и журнал решений (простой список в README проекта или файле markdown) делают pipeline удобным для сопровождения и аудита. Чистый, документированный код — это настоящий результат работы, а выходные файлы лишь следствие этого кода.

# Engineering decisions log
DECISIONS = '''
# Data Cleaning & Feature Engineering Decisions

## Duplicate handling
Kept first occurrence of duplicate order_id (most likely the original order).

## Outlier capping
Unit price capped at Q3 + 3*IQR (not 1.5*IQR) because price distribution
has legitimate high-value enterprise orders that should not be removed.

## Rare category threshold: 0.5%
Values below 0.5% of total orders collapsed to "Other" to keep charts readable
and avoid spurious significance in category-level tests.

## Cohort assignment
Cohort = first purchase calendar month (not signup month), because many users
sign up but do not purchase until months later.
'''
print(DECISIONS)

Быстрая проверка

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

Повторение урока

В этом уроке Вы узнали, что модульные функции очистки (удаление дубликатов, ограничение выбросов, стандартизация категорий) принимают и возвращают DataFrame, что упрощает их тестирование; создание признаков добавляет составляющие даты, выручку по позиции заказа, когорты клиентов и сводную статистику; а утверждения для проверки схемы контролируют переход от очистки к анализу. Далее мы вычислим основные KPI проекта: ежемесячное удержание по когортам, выручку по категориям и число активных пользователей за скользящий период.

Часто задаваемые вопросы

Урок «Очистка данных и конструирование признаков» бесплатный?

Да — полный текст урока «Очистка данных и конструирование признаков» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Pandas & NumPy Academy, подпишись на CoddyKit PRO. Курс Pandas & NumPy Academy содержит 4 уроков всего.

Чему я научусь в уроке «Очистка данных и конструирование признаков»?

Примените расширенный контрольный список очистки, создайте признаки даты и столбцы с отношениями, а затем проверьте очищенный набор данных с помощью утверждений Ты практикуешь Pandas & NumPy Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Pandas & NumPy Academy?

Предыдущий опыт не требуется. Pandas & NumPy Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «Очистка данных и конструирование признаков»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Pandas & NumPy Academy?

Да. Каждый урок Pandas & NumPy Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Настройка проекта и загрузка данных
  2. Очистка данных и конструирование признаков
  3. Анализ и вычисление KPI
  4. Финальная визуализация и экспорт отчёта
← Назад к Pandas & NumPy Academy