13. Conditional aggregation and `pivot`

📖 Reading · 3 min
💡 Every code box below is live — edit it and hit Run.

Two techniques for turning long data into wide summaries.

Conditional aggregation with when

Sometimes you want to sum only some rows within each group — revenue from one category, count of a certain status. Wrap the value in F.when(...) so non-matching rows contribute nothing:

orders.dropDuplicates().groupBy("country").agg(
    F.sum(F.when(F.col("category") == "electronics", F.col("quantity")).otherwise(0)).alias("electronics_qty"),
    F.sum(F.when(F.col("category") == "grocery", F.col("quantity")).otherwise(0)).alias("grocery_qty"),
).show()

when(condition, value).otherwise(other) is PySpark's CASE WHEN. Here each sum adds the quantity only for its category and 0 elsewhere — so one pass over the data produces several category columns side by side.

pivot — categories become columns

pivot does the same reshape declaratively: pick a column whose values become columns. Count orders per country, broken out by category:

orders.dropDuplicates().groupBy("country").pivot("category").agg(F.count("*")).show()

Each distinct category value (books, electronics, …) becomes its own column; empty cells are null (no orders of that category from that country). Pivots are perfect for cross-tabs and reports — a country × category grid in one line.

Tip. If you know the values you want as columns, pass them: pivot("category", ["electronics", "grocery"]). It's faster (Spark skips a scan to discover them) and pins the column order.

Your turn

Build a country × category grid of total quantity: group deduplicated orders by country, pivot on category, and aggregate sum("quantity"). Assign to result.

result = orders  # <- dropDuplicates, groupBy country, pivot category, agg sum(quantity)
result.show()
result = (
    orders.dropDuplicates()
    .groupBy("country")
    .pivot("category")
    .agg(F.sum("quantity"))
)