Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Join and rank dataframe results

An order table and a price table usually have different shapes. Join them by product, derive revenue, then group and rank the results. These operations stay inside the optional Polars engine until collect().

Methods borrow their inputs automatically, including temporary expressions. The example uses named intermediate plans to keep the steps readable; each step still belongs to one lazy query.

import std.dataframe as df

def main() -> Result[(), df.DataFrameError | AllocError | IoError]:
    orders = df.frame([df.column_i64("product", [1, 2, 1, 3]?)?, df.column_i64("units", [2, 1, 3, 5]?)?]?)?
    prices = df.frame([df.column_i64("product", [1, 2]?)?, df.column_f64("price", [10.0, 25.0]?)?]?)?
    keys = [df.col("product")?]?
    joined = orders.lazy()?.join(prices.lazy()?, keys, keys, how=df.JoinKind.Left)?
    revenue = df.col("price")?.fill_null(df.lit(0.0)?)?.mul(df.col("units")?)?.alias("revenue")?
    enriched = joined.with_columns([revenue]?)?
    totals = enriched.group_by(keys, [df.col("revenue")?.sum()?.alias("total")?]?)?
    ranking = [df.SortKey(df.col("total")?, descending=True), df.SortKey(df.col("product")?)]?
    best = totals.sort(ranking)?.limit(2)?.collect()?
    print(best.values_i64("product")?)?
    print(best.values_f64("total")?)?
    Ok(())
[1, 2]
[50.0, 25.0]

The left join keeps product 3 even though it has no price. This example deliberately treats a missing price as zero with fill_null; a real application may instead reject or separately report unpriced orders. The default inner join would drop unmatched orders.

Duplicate keys produce every matching pair. The price table here has one row per product; duplicate price rows would multiply revenue contributions. The join does not validate uniqueness. Null keys do not match unless you pass nulls_equal=True.

Both key columns survive the join. Since both are named product, the right one becomes product_right; use suffix="_price" to choose another suffix. A suffix collision is an error, never silent replacement.

The ranking sorts totals descending, then product ascending to break ties. Nulls go last by default; each SortKey can specify nulls_last=False. Sorting is stable for equal keys, but a join or group has no promised input order, so use a meaningful tie-breaking key when you need reproducible output.

For pagination, replace limit(2) with slice(2, 2) to skip two rows and take up to two more. Dataframe slicing takes an offset and count, not start/stop endpoints. Negative offsets count from the end; invalid negative lengths return an error. See the query contracts.

Continue with Membership and full joins to filter by another dataset or reconcile unmatched rows from both sides.