Pandas & NumPy Academy · Урок

Проверка схемы и утверждения

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

Урок 4 из 413 шагов

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

Почему важна проверка схемы

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

import pandas as pd
import numpy as np

df = pd.read_parquet('sales_treated.parquet')
print('Loaded:', df.shape)
print(df.dtypes)

Проверка обязательных столбцов

Самая базовая проверка — убедиться, что присутствуют все обязательные столбцы. Сохраните ожидаемый набор столбцов в конфигурации и проверьте, что он является подмножеством фактических столбцов. Такая проверка сразу обнаруживает переименования и удаления в начале конвейера, ещё до того, как последующий код попытается обратиться к отсутствующим столбцам и вызовет непонятную ошибку KeyError где-то глубоко в конвейере.

REQUIRED_COLUMNS = {'order_id', 'order_date', 'customer_id',
                    'product', 'category', 'quantity', 'unit_price', 'revenue'}

missing = REQUIRED_COLUMNS - set(df.columns)
assert not missing, f'Missing required columns: {missing}'
print('All required columns present.')

Проверка типов данных столбцов

После проверки обязательных столбцов проверьте их типы данных. Если столбец с датами загружен как object, это означает, что не был вызван pd.to_datetime(). Если столбец с идентификаторами хранится как float, а не как int64, часто это указывает на наличие значений NaN, из-за которых невозможно хранить данные как целые числа. Для наиболее важных столбцов задавайте проверки типов с помощью assert df['col'].dtype == expected_type.

assert pd.api.types.is_datetime64_any_dtype(df['order_date']), \
    'order_date must be datetime'
assert pd.api.types.is_numeric_dtype(df['revenue']), \
    'revenue must be numeric'
assert df['order_id'].dtype == object or pd.api.types.is_integer_dtype(df['order_id']), \
    'order_id must be string or int'
print('Dtype checks passed.')

Ограничения на нулевые значения

Ключевые столбцы, такие как order_id, order_date и revenue, не должны содержать нулевых значений. Для каждого из них проверьте df['col'].notna().all(). Чтобы сообщение проверки помогало устранить проблему, укажите в нём количество нулевых значений: так оператор конвейера поймёт масштаб проблемы, а не только узнает о том, что проверка завершилась неудачно.

NOT_NULL_COLS = ['order_id', 'order_date', 'revenue', 'customer_id']

for col in NOT_NULL_COLS:
    null_count = df[col].isna().sum()
    assert null_count == 0, f'{col} has {null_count} null values'

print('Non-null checks passed.')

Проверка диапазонов числовых столбцов

Для числовых столбцов часто существуют допустимые диапазоны значений. Выручка не может быть отрицательной. Количество должно быть положительным целым числом. Цена за единицу должна быть больше нуля. Явно проверяйте эти ограничения: строка с отрицательной выручкой, которая пройдёт проверку, уменьшит итоговые суммы во всех последующих агрегированиях, причём никаких ошибок не возникнет. Проверки диапазонов на раннем этапе обнаруживают ошибки ввода данных и сбои в вышестоящих системах.

assert (df['revenue'] >= 0).all(), 'Negative revenue found'
assert (df['quantity'] > 0).all() or df['is_return'].any(), \
    'Non-positive quantity without return flag'
assert (df['unit_price'] > 0).all(), 'Zero or negative unit price found'

print('Range checks passed.')

Проверка уникальности ключей

После удаления дубликатов значения order_id должны быть уникальными. Проверьте df['order_id'].is_unique, чтобы убедиться, что это инвариант сохраняется при каждом запуске конвейера. Нарушение уникальности после удаления дубликатов указывает на ошибку в логике дедупликации или на новый источник данных, который не был очищен перед объединением с основным набором данных.

assert df['order_id'].is_unique, \
    f'order_id not unique: {df.duplicated(subset=["order_id"]).sum()} duplicates'

print('Uniqueness check passed.')

Проверка категориальных значений

Для столбцов с конечным набором допустимых значений, например region или category, проверьте, что каждое значение входит в разрешённый набор. Это обнаруживает неожиданные значения, появившиеся после переноса системы или изменения процесса ввода данных в вышестоящей системе. Определите допустимые наборы в конфигурации конвейера, чтобы их было легко обновить при расширении бизнеса на новые регионы.

VALID_REGIONS = {'North', 'South', 'East', 'West', 'Central'}
VALID_CATEGORIES = {'electronics', 'apparel', 'home', 'sports', 'beauty', 'other'}

assert df['region'].isin(VALID_REGIONS).all(), \
    f'Invalid regions: {df[~df["region"].isin(VALID_REGIONS)]["region"].unique()}'
assert df['category'].isin(VALID_CATEGORIES).all(), \
    'Invalid categories found'

print('Categorical checks passed.')

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

Проверьте, что все даты находятся в ожидаемом периоде для этого набора данных. Заказ с датой в будущем невозможен; заказ с датой до основания компании указывает на повреждённую запись. Определите MIN_DATE и MAX_DATE в конфигурации и проверьте, что столбец находится в заданных границах. Это также обнаруживает даты начала эпохи Unix (1970-01-01), возникшие из-за неправильного преобразования временных меток.

MIN_DATE = pd.Timestamp('2020-01-01')
MAX_DATE = pd.Timestamp('today')

assert (df['order_date'] >= MIN_DATE).all(), 'Date before minimum found'
assert (df['order_date'] <= MAX_DATE).all(), 'Future date found'

print(f'Date range: {df["order_date"].min()} to {df["order_date"].max()}')

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

Резкое изменение количества строк по сравнению с предыдущим запуском конвейера — надёжный признак проблемы в вышестоящей системе. Сохраните количество строк предыдущего запуска в файле конфигурации и проверьте, что новое значение находится в допустимом диапазоне, например в пределах ±20 % от исторического значения. Если между запусками набор данных потерял 50 % строк, это почти наверняка означает, что экспорт данных неисправен.

EXPECTED_MIN_ROWS = 5000
EXPECTED_MAX_ROWS = 200000

assert EXPECTED_MIN_ROWS <= len(df) <= EXPECTED_MAX_ROWS, \
    f'Row count {len(df)} outside expected range [{EXPECTED_MIN_ROWS}, {EXPECTED_MAX_ROWS}]'

print(f'Row count check passed: {len(df)} rows')

Объединение проверок в функцию validate

Соберите все проверки в одну функцию validate(df), которую можно вызывать в начале каждого этапа конвейера. Если проверка не пройдена, она вызывает AssertionError с понятным описанием проблемы. Такой подход делает конвейер самодокументируемым: функция проверки представляет собой машиночитаемый контракт схемы для DataFrame на данном этапе.

def validate_sales_df(df):
    assert not (REQUIRED_COLUMNS - set(df.columns)), 'Missing columns'
    assert df['order_id'].is_unique, 'Duplicate order IDs'
    assert (df['revenue'] >= 0).all(), 'Negative revenue'
    assert df['region'].isin(VALID_REGIONS).all(), 'Invalid region'
    print(f'Validation passed: {len(df)} rows, {len(df.columns)} columns')

validate_sales_df(df)

Корректная регистрация сбоев проверки

В рабочих конвейерах жёсткое завершение из-за assert допустимо при разработке, но нежелательно в запланированной задаче. Замените отдельные проверки блоками try/except AssertionError, которые записывают сообщение об ошибке и при необходимости отправляют уведомление перед завершением работы. Благодаря этому система мониторинга фиксирует причину сбоя, а не только трассировку необработанного исключения.

import logging

logging.basicConfig(level=logging.INFO)

def validate_with_logging(df):
    checks = [
        (lambda d: d['order_id'].is_unique, 'Duplicate order IDs'),
        (lambda d: (d['revenue'] >= 0).all(), 'Negative revenue found'),
    ]
    for check_fn, msg in checks:
        try:
            assert check_fn(df), msg
        except AssertionError as e:
            logging.error(f'VALIDATION FAILED: {e}')
            raise

validate_with_logging(df)
print('All checks passed.')

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

Проверьте, насколько хорошо Вы усвоили концепции анализа данных из этого урока.

Итоги урока

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

Можно начать бесплатно

Изучай Python с ИИ-репетитором — бесплатно

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

Курсы
30
Уроки
120

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

Урок «Проверка схемы и утверждения» бесплатный?

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

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

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

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

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

Сколько времени занимает урок «Проверка схемы и утверждения»?

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

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

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

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

  1. Поиск и удаление дубликатов
  2. Поиск и обработка выбросов
  3. Приведение несогласованных категорий к единому виду
  4. Проверка схемы и утверждения
← Назад к Pandas & NumPy Academy