Pandas & NumPy Academy · Lektion

Metodekæder med pipe()

Skriv læsbare datapipelines med pipe() for at kæde brugerdefinerede funktioner sammen med indbyggede Pandas-metoder.

Lektion 4 af 413 trin

Metodekæder med pipe() er en gratis Pandas & NumPy Academy-lektion på CoddyKit. Dette er lektion 4 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i Pandas & NumPy Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Pandas & NumPy Academy-kurset indeholder 4 lektioner i alt.

Problemet med mellemliggende variabler

En datapipeline til datarensning uden pipe() ophober ofte mange mellemliggende variabler: df1 = clean(df), df2 = transform(df1), df3 = enrich(df2). Disse variabler fylder i navnerummet, gør fejlfinding vanskeligere og frister udviklere til at genbruge dem forkert. Resultatet er kode, der er svær at læse fra top til bund som en række transformationer.

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)

Introduktion til pipe()

DataFrame.pipe(func) kalder func(df) og returnerer resultatet, så du kan kæde brugerdefinerede funktioner på samme måde, som du kæder indbyggede Pandas-metoder som .dropna().query(). Den vigtigste fordel er, at hvert transformationstrin er tydeligt og let at læse fra venstre mod højre — eller fra top til bund, når det formateres med parenteser — så den logiske rækkefølge i pipelinen afspejles.

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)

Videregivelse af argumenter gennem pipe()

Send ekstra argumenter til den funktion, der indgår i pipelinen, ved hjælp af nøgleordsargumenter efter funktionsnavnet: df.pipe(func, arg1=val1). Funktionens signatur skal acceptere df som sin første parameter. Parameteriserede funktioner gør pipelinen konfigurerbar: Du kan ændre tærskler, kolonnenavne eller adfærd uden at ændre funktionens krop, blot ved at ændre argumenterne i pipe-kaldet.

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)

Kombination af pipe() med indbyggede metoder

Styrken ved pipe() er, at den integreres problemfrit med indbyggede Pandas-metoder i den samme kæde. Du kan blande .dropna(), .query(), .rename() og .pipe(custom_func) i vilkårlig rækkefølge. Det gør kæden både kortfattet (fordi du bruger indbyggede metoder, hvor det er muligt) og fleksibel (fordi du kan bruge brugerdefinerede funktioner, når de indbyggede metoder ikke rækker).

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

Fejlfinding i en pipe()-kæde

Det kan være vanskeligt at fejlfinde en lang kæde, fordi du ikke kan undersøge mellemtilstande ved at indsætte en print-sætning midt i kæden. En løsning er at skrive en gennemløbende fejlfindingsfunktion, der udskriver oplysninger om form og kolonner og derefter returnerer DataFrame-objektet uændret. Indsæt den et vilkårligt sted i kæden for at undersøge tilstanden på det trin uden at afbryde kæden.

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

Opbygning af et komplet databehandlingsforløb

Kombiner alle rensningstrin i én enkelt forløbsfunktion ved hjælp af pipe(). Hvis du omslutter kæden i en funktion kaldet clean_pipeline(df), kan du teste forløbet som en samlet enhed. Kald den med et råt DataFrame-objekt, og modtag et renset. Dette mønster følger ETL-paradigmet (Extract, Transform, Load), som bruges i datateknik i produktionsmiljøer.

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

Vigtige forskelle mellem pipe() og apply()

pipe(func) sender hele DataFrame-objektet til func og forventer et DataFrame-objekt (eller et transformeret objekt) retur. apply(func, axis=1) sender én række ad gangen. Brug pipe() til transformationer af hele DataFrame-objektet, som bevarer den samme form (eller ændrer den med vilje), og brug apply() til beregninger på række- eller kolonneniveau. De supplerer hinanden, men konkurrerer ikke.

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

Genanvendelige komponenter i databehandlingsforløb

Skriv hvert trin i databehandlingsforløbet som en ren funktion — uden global tilstand, hvor funktionen modtager et DataFrame-objekt og returnerer et DataFrame-objekt. Rene funktioner er nemme at enhedsteste: Kald dem med et lille test-DataFrame-objekt, og kontrollér resultatets form og kolonneværdier. Et bibliotek med testede, genanvendelige forløbsfunktioner gør analysen af nye datasæt med lignende rensekrav markant hurtigere.

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)

Logning af trin i databehandlingsforløb med pipe()

Tilføj struktureret logning i hver forløbsfunktion, så du kan kontrollere enhver transformation i produktion. Medtag antallet af inputrækker, antallet af outputrækker og relevante statistikker (f.eks. rækker, der blev fjernet af et filter). Det giver dig et komplet spor af hver kørsel af databehandlingsforløbet uden behov for en ekstern orkestrator til grundlæggende revisionsspor.

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

Betingede trin i et databehandlingsforløb

Nogle gange skal et rensningstrin kun køres baseret på et flag eller på indholdet af dataene. Du kan tilføje betingede trin til en pipe-kæde ved at indsætte en funktion, der enten lader dataene passere eller transformerer dem: Den kontrollerer en betingelse og anvender enten en transformation eller returnerer DataFrame-objektet uændret. På den måde bevares kædestrukturen, samtidig med at valgfrie trin understøttes.

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)

Eksport af resultatet fra databehandlingsforløbet

Det sidste trin i en pipe()-kæde er ofte en eksport. Du kan kæde en brugerdefineret eksportfunktion sammen ved hjælp af pipe() eller blot kalde den indbyggede Pandas-eksportmetode efter kæden. Hvis du bruger et trin med pipe(save_to_parquet), bliver eksporten en del af dokumentationen for kæden, og du sikrer, at den altid køres på det endelige rensede DataFrame-objekt og ikke på en mellemversion.

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

Hurtigt tjek

Test din forståelse af begreberne inden for dataanalyse fra denne lektion.

Opsummering af lektionen

I denne lektion har du lært: at bruge pipe() til at kæde brugerdefinerede funktioner sammen med indbyggede Pandas-metoder, at opbygge genanvendelige, parameteriserede og testbare trin i databehandlingsforløb som rene funktioner og at tilføje fejlfindingslogning og betingede trin i en pipe-kæde. Dernæst undersøger vi, hvordan transformations­trin struktureres som funktioner i et ETL-forløb til produktion.

Gratis at komme i gang

Lær Python med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
30
Lektioner
120

Ofte stillede spørgsmål

Er lektionen “Metodekæder med pipe()” gratis?

Ja — hele teksten til “Metodekæder med pipe()” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af Pandas & NumPy Academy-kurset, skal du opgradere til CoddyKit PRO. Pandas & NumPy Academy-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Metodekæder med pipe()”?

Skriv læsbare datapipelines med pipe() for at kæde brugerdefinerede funktioner sammen med indbyggede Pandas-metoder. Du øver dig i Pandas & NumPy Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Pandas & NumPy Academy?

Der kræves ingen tidligere erfaring. Pandas & NumPy Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 4 af 4.

Hvor lang tid tager lektionen “Metodekæder med pipe()”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Pandas & NumPy Academy-lektion?

Ja. Alle Pandas & NumPy Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. apply() på kolonner og rækker
  2. apply() med GroupBy
  3. map() og applymap() til elementvise operationer
  4. Metodekæder med pipe()
← Tilbage til Pandas & NumPy Academy