Pandas & NumPy Academy · Lekcja

Walidacja schematu i asercje

Pisz asercje sprawdzające zakresy kolumn, ograniczenia wartości niepustych i unikatowe klucze, uruchamiane na początku każdego potoku.

Lekcja 4 z 413 kroki

Walidacja schematu i asercje to bezpłatna lekcja Pandas & NumPy Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Pandas & NumPy Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Pandas & NumPy Academy zawiera 4 lekcji w sumie.

Dlaczego walidacja schematu ma znaczenie

Potok danych przetwarza nowe dane automatycznie, często bez udziału człowieka. Jeśli schemat pliku wejściowego się zmieni — kolumna zostanie przemianowana, format daty ulegnie zmianie albo pojawi się nowa kategoria — potok powinien wyraźnie zgłosić błąd, zamiast generować po cichu niepoprawne wyniki. Walidacja schematu za pomocą asercji to mechanizm egzekwujący kontrakty między producentami a odbiorcami danych i wykrywający problemy możliwie najwcześniej.

import pandas as pd
import numpy as np

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

Sprawdzanie wymaganych kolumn

Najbardziej podstawowa walidacja polega na sprawdzeniu, czy obecne są wszystkie wymagane kolumny. Oczekiwany zbiór kolumn należy przechowywać w konfiguracji i sprawdzać asercją, czy jest podzbiorem rzeczywistych kolumn. Kontrola ta natychmiast wykrywa zmiany nazw i usunięcia kolumn na początku potoku, zanim dalszy kod spróbuje uzyskać dostęp do brakujących kolumn i zgłosi mylący błąd KeyError głęboko wewnątrz potoku.

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.')

Asercje dotyczące typów danych kolumn

Po sprawdzeniu wymaganych kolumn należy zweryfikować ich typy danych. Kolumna dat załadowana jako object oznacza, że nie wywołano pd.to_datetime(). Kolumna identyfikatora przechowywana jako float zamiast int64 często wskazuje na obecność wartości NaN, które uniemożliwiły przechowywanie danych w typie całkowitym. Dla najważniejszych kolumn należy zapisać asercje typów za pomocą 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.')

Ograniczenia dotyczące wartości null

Kluczowe kolumny, takie jak order_id, order_date i revenue, nigdy nie powinny zawierać wartości null. Dla każdej z nich należy użyć asercji df['col'].notna().all(). Aby komunikat asercji ułatwiał podjęcie działania, należy uwzględnić liczbę wartości null, tak aby operator potoku znał skalę problemu, a nie tylko informację o niepowodzeniu asercji.

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.')

Sprawdzanie zakresów kolumn liczbowych

Kolumny liczbowe często mają prawidłowe zakresy wynikające z reguł biznesowych. Przychód musi być nieujemny. Ilość musi być dodatnią liczbą całkowitą. Cena jednostkowa musi być większa od zera. Należy jawnie sprawdzić te ograniczenia — wiersz z ujemnym przychodem, który przejdzie dalej, zaniży sumy we wszystkich kolejnych agregacjach bez zgłoszenia jakiegokolwiek błędu. Kontrola zakresów wcześnie wykrywa błędy wprowadzania danych i usterki systemów nadrzędnych.

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.')

Asercje dotyczące unikalnych kluczy

Po usunięciu duplikatów wartość order_id powinna być unikalna. Należy użyć asercji df['order_id'].is_unique, aby sprawdzić, czy ta niezmienniczość jest zachowana przy każdym uruchomieniu potoku. Naruszenie unikalności po usunięciu duplikatów wskazuje na błąd w logice usuwania duplikatów albo na nowe źródło danych, które nie zostało oczyszczone przed połączeniem z głównym zbiorem danych.

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

print('Uniqueness check passed.')

Asercje dotyczące wartości kategorii

W przypadku kolumn o skończonym zbiorze prawidłowych wartości — takich jak region lub category — należy sprawdzić asercją, czy każda wartość należy do dozwolonego zbioru. Pozwala to wykryć nieprawidłowe wartości pojawiające się po migracji systemu lub zmianie sposobu wprowadzania danych w systemie nadrzędnym. Prawidłowe zbiory należy definiować w konfiguracji potoku, aby można je było łatwo aktualizować, gdy firma wejdzie na nowe rynki.

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.')

Asercje dotyczące zakresu dat

Należy sprawdzić, czy wszystkie daty mieszczą się w oczekiwanym okresie dla danego zbioru danych. Zamówienie z datą w przyszłości jest niemożliwe, a zamówienie datowane przed założeniem firmy wskazuje na uszkodzony rekord. W konfiguracji należy zdefiniować MIN_DATE i MAX_DATE, a następnie sprawdzić asercją, czy kolumna mieści się w tych granicach. Pozwala to również wykrywać daty odpowiadające zerowej epoce Unix (1970-01-01), wynikające z nieprawidłowej konwersji znaczników czasu.

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()}')

Kontrola liczby wierszy

Nagła zmiana liczby wierszy względem poprzedniego uruchomienia potoku jest silnym sygnałem problemu w systemie nadrzędnym. Liczbę wierszy z poprzedniego uruchomienia należy zapisać w pliku konfiguracyjnym i sprawdzić asercją, czy nowa liczba mieści się w przedziale tolerancji — na przykład w granicach ±20% względem wartości historycznej. Zbiór danych, który między uruchomieniami traci 50% wierszy, niemal na pewno wskazuje na uszkodzony eksport danych.

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')

Grupowanie kontroli w funkcji validate

Wszystkie asercje należy zebrać w jednej funkcji validate(df), którą można wywołać na początku każdego etapu potoku. Każda kontrola w przypadku niepowodzenia zgłasza AssertionError z opisowym komunikatem. Ten wzorzec sprawia, że potok sam dokumentuje swoje działanie: funkcja walidacyjna jest czytelnym maszynowo kontraktem schematu dla DataFrame na danym etapie.

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)

Eleganckie rejestrowanie błędów walidacji

W potokach produkcyjnych gwałtowne przerwanie działania przez assert jest akceptowalne podczas programowania, ale niepożądane w zadaniu uruchamianym według harmonogramu. Należy zastąpić bezpośrednie asercje blokami try/except AssertionError, które rejestrują komunikat błędu i opcjonalnie wysyłają alert przed zakończeniem działania. Dzięki temu system monitorowania może przechwycić przyczynę niepowodzenia, a nie tylko ślad stosu nieobsłużonego wyjątku.

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.')

Szybkie sprawdzenie

Sprawdź swoją wiedzę na temat koncepcji analizy danych omówionych w tej lekcji.

Podsumowanie lekcji

W tej lekcji nauczyłeś się: sprawdzać wymagane kolumny, dtypes, ograniczenia dotyczące wartości null i poprawność zakresów, weryfikować unikalne klucze, wartości kategorii i zakresy dat oraz grupować wszystkie kontrole w wielokrotnie używanej funkcji validate() z rejestrowaniem zdarzeń. Następnie omówimy niestandardowe agregacje z użyciem apply() dla kolumn i wierszy.

Bezpłatny start

Ucz się Python dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
30
Lekcje
120

Często zadawane pytania

Czy lekcja „Walidacja schematu i asercje” jest bezpłatna?

Tak — pełny tekst „Walidacja schematu i asercje” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Pandas & NumPy Academy, przejdź na CoddyKit PRO. Kurs Pandas & NumPy Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Walidacja schematu i asercje”?

Pisz asercje sprawdzające zakresy kolumn, ograniczenia wartości niepustych i unikatowe klucze, uruchamiane na początku każdego potoku. Ćwiczysz Pandas & NumPy Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Pandas & NumPy Academy?

Nie wymagamy żadnego doświadczenia. Pandas & NumPy Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Walidacja schematu i asercje”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Pandas & NumPy Academy?

Tak. Każda lekcja Pandas & NumPy Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Wykrywanie i usuwanie duplikatów
  2. Wykrywanie i obsługa wartości odstających
  3. Ujednolicanie niespójnych kategorii
  4. Walidacja schematu i asercje
← Powrót do Pandas & NumPy Academy