0Pricing
Pandas & NumPy Academy · Lezione

Concatenare metodi con pipe()

Scriva pipeline leggibili per la trasformazione dei dati usando pipe() per concatenare funzioni personalizzate e metodi nativi di Pandas.

Concatenare metodi con pipe() è una lezione Pandas & NumPy Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Pandas & NumPy Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Pandas & NumPy Academy include 4 lezioni in totale.

Il problema delle variabili intermedie

Una pipeline di pulizia dei dati senza pipe() spesso accumula molte variabili intermedie: df1 = clean(df), df2 = transform(df1), df3 = enrich(df2). Queste variabili ingombrano lo spazio dei nomi, rendono più difficile il debug e inducono gli sviluppatori a riutilizzarle in modo errato. Il risultato è un codice difficile da leggere dall'inizio alla fine come una sequenza di trasformazioni.

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)

Introduzione a pipe()

DataFrame.pipe(func) chiama func(df) e restituisce il risultato, consentendo di concatenare funzioni personalizzate nello stesso modo in cui si concatenano i metodi nativi di Pandas, come .dropna().query(). Il vantaggio principale è che ogni passaggio della trasformazione è esplicito e leggibile da sinistra a destra, o dall'alto verso il basso quando viene formattato usando le parentesi, rispecchiando l'ordine logico della pipeline.

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)

Passare argomenti tramite pipe()

Passi argomenti aggiuntivi alla funzione a cui applica pipe usando argomenti con nome dopo il nome della funzione: df.pipe(func, arg1=val1). La firma della funzione deve accettare df come primo parametro. Le funzioni parametrizzate rendono la pipeline configurabile: è possibile modificare soglie, nomi di colonne o comportamento senza modificare il corpo della funzione, semplicemente cambiando gli argomenti della chiamata a 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)

Combinare pipe() con i metodi nativi

Il punto di forza di pipe() è che si integra perfettamente con i metodi nativi di Pandas nella stessa catena. È possibile combinare .dropna(), .query(), .rename() e .pipe(custom_func) in qualsiasi ordine. In questo modo la catena è concisa (usa i metodi integrati quando possibile) e flessibile (ricorre a funzioni personalizzate quando i metodi integrati non sono sufficienti).

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

Debug di una catena pipe()

Eseguire il debug di una catena lunga può essere complesso, perché non è possibile ispezionare gli stati intermedi inserendo un'istruzione print nel mezzo. Una soluzione consiste nello scrivere una funzione di debug pass-through che stampa le informazioni sulla forma e sulle colonne, quindi restituisce il DataFrame invariato. Inserendola in qualsiasi punto della catena, è possibile ispezionare lo stato in quel passaggio senza interrompere la catena.

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

Creazione di una pipeline completa di pulizia

Combini tutti i passaggi di pulizia in un'unica funzione pipeline usando pipe(). Racchiudere la catena in una funzione chiamata clean_pipeline(df) rende la pipeline testabile come un'unità. La si richiama con un DataFrame grezzo e si ottiene un DataFrame pulito. Questo pattern segue il paradigma ETL (Extract, Transform, Load) utilizzato nella data engineering in produzione.

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() e apply(): differenze principali

pipe(func) passa l'intero DataFrame a func e si aspetta in restituzione un DataFrame (o un oggetto trasformato). apply(func, axis=1) passa una riga alla volta. Utilizzi pipe() per trasformazioni che coinvolgono l'intero DataFrame e ne mantengono la stessa forma (o la modificano intenzionalmente), e apply() per calcoli a livello di riga o di colonna. Sono strumenti complementari, non alternativi.

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

Componenti di pipeline riutilizzabili

Scriva ogni passaggio della pipeline come una funzione pura: senza stato globale, riceve un DataFrame e restituisce un DataFrame. Le funzioni pure sono facili da testare con unit test: le si richiama con un piccolo DataFrame di test e si verificano la forma dell'output e i valori delle colonne. Una libreria di funzioni di pipeline testate e riutilizzabili accelera notevolmente l'analisi di nuovi dataset che condividono requisiti di pulizia simili.

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)

Registrazione dei passaggi della pipeline con pipe()

Aggiunga il logging strutturato all'interno di ogni funzione della pipeline, così da poter verificare ogni trasformazione in produzione. Includa il numero di righe in ingresso, il numero di righe in uscita e tutte le statistiche pertinenti (ad esempio, le righe eliminate da un filtro). In questo modo ottiene una traccia completa di ogni esecuzione della pipeline senza dover ricorrere a un orchestratore di workflow esterno per le verifiche di base.

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

Passaggi condizionali in una pipeline

A volte un passaggio di pulizia deve essere eseguito solo in base a un flag o al contenuto dei dati. È possibile aggiungere passaggi condizionali a una catena pipe inserendo una funzione di identità o trasformazione: verifica una condizione e applica una trasformazione oppure restituisce il DataFrame invariato. In questo modo la struttura della catena rimane intatta, pur supportando passaggi opzionali.

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)

Esportazione del risultato della pipeline

L'ultimo passaggio di una catena pipe() è spesso un'esportazione. È possibile concatenare una funzione di esportazione personalizzata usando pipe() oppure chiamare semplicemente il metodo nativo di esportazione di Pandas dopo la catena. L'uso di un passaggio pipe(save_to_parquet) mantiene l'esportazione documentata come parte della catena e garantisce che venga sempre eseguita sul DataFrame pulito finale, non su una versione intermedia.

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

Verifica rapida

Verifichi la Sua comprensione dei concetti di analisi dei dati trattati in questa lezione.

Riepilogo della lezione

In questa lezione ha imparato a: usare pipe() per concatenare funzioni personalizzate con i metodi nativi di Pandas, creare passaggi di pipeline riutilizzabili, parametrizzati e testabili sotto forma di funzioni pure e aggiungere logging di debug e passaggi condizionali all'interno di una catena pipe. Nel prossimo argomento esploreremo come strutturare i passaggi di trasformazione come funzioni per una pipeline ETL destinata alla produzione.

Domande Frequenti

La lezione «Concatenare metodi con pipe()» è gratuita?

Sì — il testo completo di «Concatenare metodi con pipe()» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Pandas & NumPy Academy, passa a CoddyKit PRO. Il corso Pandas & NumPy Academy include 4 lezioni in totale.

Cosa imparerò in «Concatenare metodi con pipe()»?

Scriva pipeline leggibili per la trasformazione dei dati usando pipe() per concatenare funzioni personalizzate e metodi nativi di Pandas. Eserciti Pandas & NumPy Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Pandas & NumPy Academy?

Non è richiesta alcuna esperienza precedente. Pandas & NumPy Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.

Quanto tempo richiede la lezione «Concatenare metodi con pipe()»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Pandas & NumPy Academy?

Sì. Ogni lezione Pandas & NumPy Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. apply() su colonne e righe
  2. apply() con GroupBy
  3. map() e applymap() per operazioni elemento per elemento
  4. Concatenare metodi con pipe()
← Torna a Pandas & NumPy Academy