Łańcuchowe wywoływanie metod z pipe()
Pisz czytelne potoki transformacji danych, używając pipe() do łączenia niestandardowych funkcji z wbudowanymi metodami Pandas.
Łańcuchowe wywoływanie metod z pipe() 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.
Problem ze zmiennymi pośrednimi
Potok czyszczenia danych bez pipe() często prowadzi do nagromadzenia wielu zmiennych pośrednich: df1 = clean(df), df2 = transform(df1), df3 = enrich(df2). Zmienne te zaśmiecają przestrzeń nazw, utrudniają debugowanie i skłaniają programistów do ich nieprawidłowego ponownego użycia. W rezultacie kod jest trudny do odczytania od góry do dołu jako sekwencja przekształceń.
import pandas as pd
df = pd.read_csv('orders.csv')
# Without pipe — intermediate variables everywhere
df1 = df.dropna(subset=['revenue'])
df2 = df1[df1['quantity'] > 0]
df3 = df2.assign(revenue_per_unit=df2['revenue'] / df2['quantity'])
print(df3.shape)Wprowadzenie do pipe()
DataFrame.pipe(func) wywołuje func(df) i zwraca wynik, umożliwiając łączenie niestandardowych funkcji w taki sam sposób jak natywnych metod Pandas, takich jak .dropna().query(). Najważniejszą korzyścią jest jawność i czytelność każdego kroku przekształcenia od lewej do prawej (lub z góry na dół, gdy kod sformatowano z użyciem nawiasów), co odzwierciedla logiczną kolejność potoku.
def drop_nulls(df):
return df.dropna(subset=['revenue'])
def filter_positive_qty(df):
return df[df['quantity'] > 0]
def add_revenue_per_unit(df):
return df.assign(revenue_per_unit=df['revenue'] / df['quantity'])
# With pipe — clean chain
df_clean = (df
.pipe(drop_nulls)
.pipe(filter_positive_qty)
.pipe(add_revenue_per_unit)
)
print(df_clean.shape)Przekazywanie argumentów przez pipe()
Dodatkowe argumenty do funkcji przekazywanej potokiem należy podać jako argumenty nazwane po nazwie funkcji: df.pipe(func, arg1=val1). Sygnatura funkcji musi przyjmować df jako pierwszy parametr. Funkcje z parametrami umożliwiają konfigurację potoku: można zmieniać progi, nazwy kolumn lub sposób działania bez modyfikowania ciała funkcji — wystarczy zmienić argumenty wywołania pipe.
def filter_by_region(df, regions):
return df[df['region'].isin(regions)]
def cap_revenue(df, upper):
df = df.copy()
df['revenue'] = df['revenue'].clip(upper=upper)
return df
df_result = (df
.pipe(filter_by_region, regions=['North', 'East'])
.pipe(cap_revenue, upper=1000)
)
print(df_result.shape)Łączenie pipe() z metodami natywnymi
Zaletą pipe() jest bezproblemowa integracja z natywnymi metodami Pandas w ramach tego samego łańcucha. Można łączyć .dropna(), .query(), .rename() i .pipe(custom_func) w dowolnej kolejności. Dzięki temu łańcuch jest zarówno zwięzły (wykorzystuje wbudowane metody tam, gdzie to możliwe), jak i elastyczny (korzysta z własnych funkcji tam, gdzie brakuje odpowiednich metod wbudowanych).
df_result = (
df
.dropna(subset=['revenue', 'order_date'])
.query('quantity > 0')
.rename(columns={'unit_price': 'price'})
.pipe(add_revenue_per_unit)
.reset_index(drop=True)
)
print(df_result.head())Debugowanie łańcucha pipe()
Debugowanie długiego łańcucha może być trudne, ponieważ nie można sprawdzić stanów pośrednich, dodając instrukcję print w jego środku. Jednym z rozwiązań jest napisanie funkcji debugowania przekazującej dane dalej, która wyświetla informacje o rozmiarze i kolumnach, a następnie zwraca niezmieniony DataFrame. Można wstawić ją w dowolnym miejscu łańcucha, aby sprawdzić jego stan na danym etapie bez przerywania działania łańcucha.
def debug(df, label=''):
print(f'[{label}] shape: {df.shape}')
print(f'[{label}] columns: {df.columns.tolist()}')
return df
df_result = (
df
.pipe(drop_nulls)
.pipe(debug, label='after drop_nulls')
.pipe(filter_positive_qty)
.pipe(debug, label='after filter')
)
print('Done')Budowanie pełnego potoku czyszczenia danych
Połącz wszystkie kroki czyszczenia w jednej funkcji potoku, używając pipe(). Umieszczenie łańcucha w funkcji o nazwie clean_pipeline(df) sprawia, że potok można testować jako całość. Wywołaj ją z surowym DataFrame'em, aby otrzymać oczyszczony DataFrame. Ten wzorzec jest zgodny z paradygmatem ETL (Extract, Transform, Load) używanym w produkcyjnej inżynierii danych.
def clean_pipeline(df):
return (
df
.dropna(subset=['order_id', 'revenue'])
.drop_duplicates(subset=['order_id'])
.query('quantity > 0 and revenue >= 0')
.pipe(add_revenue_per_unit)
.reset_index(drop=True)
)
df_clean = clean_pipeline(df)
print('Clean rows:', len(df_clean))pipe() a apply(): najważniejsze różnice
pipe(func) przekazuje cały DataFrame do func i oczekuje z powrotem DataFrame'u (lub przekształconego obiektu). apply(func, axis=1) przekazuje po jednym wierszu naraz. Używaj pipe() do przekształceń całego DataFrame'u, które zachowują ten sam kształt (lub celowo go zmieniają), a apply() do obliczeń na poziomie wierszy lub kolumn. Są to narzędzia uzupełniające się, a nie konkurencyjne.
# pipe: receives the whole DataFrame
def scale_revenue(df, factor=1.0):
df = df.copy()
df['revenue'] = df['revenue'] * factor
return df
# apply: receives one row at a time
df['revenue_x2'] = df.apply(lambda row: row['revenue'] * 2, axis=1)
df_scaled = df.pipe(scale_revenue, factor=1.1)
print('pipe scales all rows at once; apply does row-by-row')Wielokrotnego użytku komponenty potoku
Zapisuj każdy krok potoku jako funkcję czystą — bez stanu globalnego, przyjmującą DataFrame i zwracającą DataFrame. Czyste funkcje łatwo testować jednostkowo: wywołaj je z małym testowym DataFrame'em i sprawdź kształt wyniku oraz wartości kolumn. Biblioteka przetestowanych funkcji potoku wielokrotnego użytku znacznie przyspiesza analizę nowych zbiorów danych, które wymagają podobnego czyszczenia.
def normalise_strings(df, cols):
df = df.copy()
for col in cols:
df[col] = df[col].str.strip().str.lower()
return df
def parse_dates(df, cols):
df = df.copy()
for col in cols:
df[col] = pd.to_datetime(df[col])
return df
df_result = (
df
.pipe(normalise_strings, cols=['region', 'category'])
.pipe(parse_dates, cols=['order_date'])
)
print(df_result.dtypes)Rejestrowanie kroków potoku za pomocą pipe()
Dodaj ustrukturyzowane logowanie wewnątrz każdej funkcji potoku, aby móc kontrolować każdą transformację w środowisku produkcyjnym. Uwzględniaj liczbę wierszy wejściowych, liczbę wierszy wyjściowych oraz wszelkie istotne statystyki (np. liczbę wierszy odrzuconych przez filtr). Zapewnia to pełny ślad każdego uruchomienia potoku bez potrzeby korzystania z zewnętrznego orkiestratora przepływów pracy do podstawowego audytu.
import logging
logging.basicConfig(level=logging.INFO)
def logged_dropna(df, subset):
before = len(df)
df = df.dropna(subset=subset)
after = len(df)
logging.info(f'dropna: {before - after} rows removed, {after} remaining')
return df
df_clean = df.pipe(logged_dropna, subset=['revenue'])
print('Logged pipeline complete.')Warunkowe kroki w potoku
Czasami krok czyszczenia powinien być wykonywany tylko na podstawie flagi lub zawartości danych. Można dodać warunkowe kroki do łańcucha pipe, wstawiając funkcję identyczności lub transformacji: sprawdza ona warunek i albo stosuje transformację, albo zwraca DataFrame bez zmian. Pozwala to zachować strukturę łańcucha, a jednocześnie obsługiwać opcjonalne kroki.
def maybe_cap_revenue(df, cap=None):
if cap is None:
return df
df = df.copy()
df['revenue'] = df['revenue'].clip(upper=cap)
return df
CAPPING_ENABLED = True
CAP_VALUE = 1000 if CAPPING_ENABLED else None
df_result = df.pipe(maybe_cap_revenue, cap=CAP_VALUE)
print('Conditional step applied:', CAPPING_ENABLED)Eksportowanie wyniku potoku
Ostatnim krokiem łańcucha pipe() jest często eksport. Można połączyć własną funkcję eksportującą za pomocą pipe() albo po prostu wywołać natywną metodę eksportu Pandas po zakończeniu łańcucha. Użycie kroku pipe(save_to_parquet) sprawia, że eksport jest częścią dokumentacji łańcucha i gwarantuje, że zawsze zostanie wykonany na końcowym oczyszczonym DataFrame, a nie na wersji pośredniej.
def save_parquet(df, path):
df.to_parquet(path, index=False)
print(f'Saved {len(df)} rows to {path}')
return df # return df so the chain can continue if needed
df_final = (
df
.pipe(clean_pipeline)
.pipe(save_parquet, path='orders_final.parquet')
)
print('Pipeline complete.')Szybki test
Sprawdź swoje zrozumienie pojęć związanych z analizą danych z tej lekcji.
Podsumowanie lekcji
W tej lekcji nauczyłeś się: używać pipe() do łączenia własnych funkcji z natywnymi metodami Pandas, budować wielokrotnego użytku, parametryzowane i testowalne kroki potoku jako funkcje czyste oraz dodawać logowanie debugowania i kroki warunkowe wewnątrz łańcucha pipe. Następnie zajmiemy się organizowaniem kroków transformacji jako funkcji na potrzeby produkcyjnego potoku ETL.
Często zadawane pytania
Czy lekcja „Łańcuchowe wywoływanie metod z pipe()” jest bezpłatna?
Tak — pełny tekst „Łańcuchowe wywoływanie metod z pipe()” 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 „Łańcuchowe wywoływanie metod z pipe()”?
Pisz czytelne potoki transformacji danych, używając pipe() do łączenia niestandardowych funkcji z wbudowanymi metodami Pandas. Ć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 „Łańcuchowe wywoływanie metod z pipe()”?
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
- apply() dla kolumn i wierszy
- apply() z GroupBy
- map() i applymap() do operacji elementowych
- Łańcuchowe wywoływanie metod z pipe()