A data pipeline moves rows from a source to a target and cleans them on the way. Here the source is one day's export of the shop's orders, orders/2026-05-02.csv, and the target is a file the analysts can query.
Data engineers split a pipeline into three jobs, ETL, each one a small function: extract reads the rows from the source, transform cleans them (a DataFrame in, a DataFrame out, no files), and load writes them to the target. In one long script, a new source or a new cleaning rule means digging through code that does everything at once. With three functions, each change touches only one of them, and you can try transform on a few hand-made rows.
The target is a Parquet file: a table format that stores each column with its type, compressed. A CSV file is only text, so every reader guesses the types again; a Parquet file gives numbers back as numbers, and tools like DuckDB read it fast. pandas writes one with df.to_parquet(path, index=False). index=False leaves out pandas' row labels: after a filter they have gaps, and they would land in the file as an extra column, __index_level_0__.
Here is a transform for another file, customers.csv, and the two lines that use it:
def clean_customers(df):
readers = df[df["newsletter"] == "yes"]
readers["big_spender"] = readers["spent"] > 400
return readers
readers = clean_customers(pd.read_csv("customers.csv"))
readers.to_parquet("readers.parquet", index=False)
The starting code imports pandas and, at the bottom, already calls your functions: extract on orders/2026-05-02.csv (12 orders, 2 of them cancelled), transform on what it returns, and load into orders_2026-05-02.parquet. The check reads that file back with DuckDB and prints its rows and their total, then runs your three functions again on 05-01's file:
order_id | customer_id | product | quantity | unit_price | status | ordered_at | total 5012 | 78 | Plant | 2 | 15 | paid | 2026-05-02 10:06:00 | 30 5013 | 277 | Lamp | 2 | 29 | paid | 2026-05-02 12:01:00 | 58 … 5022 | 128 | Notebook | 2 | 7 | paid | 2026-05-02 20:39:00 | 14 (10 rows) orders | total 10 | 382 (1 row) The same three functions on orders/2026-05-01.csv: orders | total 10 | 274 (1 row)
Your task: write extract(path), which returns the file at path read with pd.read_csv; transform(df), which keeps the rows whose status is "paid", adds a total column (quantity times unit_price) and returns them; and load(df, path), which writes df to path with to_parquet, without the index.
Assignment
Follow the Coding Tutorial to write extract, transform and load, one line at a time.
Hintextract and transform must return their DataFrame: a function without a return gives back None, and the next function gets nothing to work on. load only writes the file, so it needs no return.
Free plan: 30 tutor messages. PRO is unlimited.
