Aggregation & Transformation
Reviewed & published by Brayan K
Aggregation collapses each group of rows into a single summary value, while transformation computes a per-group statistic and broadcasts it back so every original row keeps its place — two complementary tools that turn grouped data into insight.
Part of the free Pandas course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Learn to run lists and dictionaries of functions, give outputs clean names with named aggregation, and use transform to attach group statistics back onto each row.
What You'll Learn in This Lesson
- Run several functions with .agg([...])
- Apply different functions per column with a dict
- Name outputs with named aggregation
- Broadcast group stats with transform()
- Tell aggregation and transformation apart
- Compute a row's share of its group total
1 .agg() With Lists and Dictionaries
Pass a list of functions to .agg() to compute several summaries of the same column. Pass a dictionary to apply different functions to different columns, mapping each column name to the function(s) you want.
import pandas as pd
df = pd.DataFrame({
"team": ["A", "A", "B", "B", "B"],
"points": [10, 20, 5, 15, 25],
"minutes": [30, 22, 18, 40, 35],
})
# A list of functions on one grouped column
print(df.groupby("team")["points"].agg(["sum", "mean", "max"]))
# A dict: a different function per column
print(df.groupby("team").agg({"points": "sum", "minutes": "mean"}))
# points minutes
# team
# A 30 26.0
# B 45 31.0
# ✅ Expected output:
# sum mean max
# team
# A 30 15.0 20
# B 45 15.0 25
# points minutes
# team
# A 30 26.0
# B 45 31.02 Named Aggregation for Clean Columns
Named aggregation gives every output a tidy column name. Each keyword you pass to .agg() becomes a column, and its value is a tuple of ("column", "function"). This avoids the awkward MultiIndex column names you get from list-style agg.
import pandas as pd
df = pd.DataFrame({
"team": ["A", "A", "B", "B", "B"],
"points": [10, 20, 5, 15, 25],
})
# Each keyword -> an output column = (source_column, function)
summary = df.groupby("team").agg(
total=("points", "sum"),
average=("points", "mean"),
games=("points", "count"),
)
print(summary)
# total average games
# team
# A 30 15.0 2
# B 45 15.0 3
# ✅ Expected output:
# total average games
# team
# A 30 15.0 2
# B 45 15.0 33 transform(): Broadcasting Group Stats Back
The key difference: agg reduces each group to one row, while transform preserves shape and returns a value for every original row. That makes transform perfect for attaching a group statistic, like the group mean, back onto each row so you can compare individuals to their group.
import pandas as pd
df = pd.DataFrame({
"team": ["A", "A", "B", "B", "B"],
"points": [10, 20, 5, 15, 25],
})
# agg gives ONE row per team
print(df.groupby("team")["points"].mean()) # A 15.0, B 15.0
# transform gives the team mean on EVERY row (same length as df)
df["team_mean"] = df.groupby("team")["points"].transform("mean")
# Now compare each row to its group's mean
df["vs_mean"] = df["points"] - df["team_mean"]
print(df)
# team_mean is 15.0 for A rows and 15.0 for B rows; vs_mean shows the gap
# ✅ Expected output:
# team
# A 15.0
# B 15.0
# Name: points, dtype: float64
# team points team_mean vs_mean
# 0 A 10 15.0 -5.0
# 1 A 20 15.0 5.0
# 2 B 5 15.0 -10.0
# 3 B 15 15.0 0.0
# 4 B 25 15.0 10.0🎯 Your Turn: Group Totals on Every Row
Replace the blank so each row gets its team's total points. The expected team_total column is 30, 30, 45, 45, 45.
import pandas as pd
df = pd.DataFrame({
"team": ["A", "A", "B", "B", "B"],
"points": [10, 20, 5, 15, 25],
})
# 🎯 YOUR TURN: broadcast each team's SUM back to every row
df["team_total"] = df.groupby("team")["points"].___("sum")
print(df["team_total"].tolist())
# Expected output: [30, 30, 45, 45, 45]📋 Quick Reference
| Task | Code |
|---|---|
| Many funcs, one column | g["v"].agg(["sum", "mean"]) |
| Func per column | g.agg({a: 'sum', b: 'mean'}) |
| Named output | g.agg(total=("v", "sum")) |
| Group stat per row | g["v"].transform("mean") |
| agg vs transform | reduce vs keep shape |
🎯 Mini Challenge: Share of Group Total
Use transform to compute each sale's percentage share of its region total, then build a named-aggregation summary.
import pandas as pd
df = pd.DataFrame({
"region": ["N", "N", "S", "S"],
"amount": [30, 70, 40, 60],
})
# 1. Each row's share of its region's total (transform keeps shape)
region_total = df.groupby("region")["amount"].transform("sum")
df["pct_of_region"] = (df["amount"] / region_total * 100).round(1)
print(df)
# N rows: 30.0% and 70.0%; S rows: 40.0% and 60.0%
# 2. A clean summary table with named aggregation
summary = df.groupby("region").agg(
total=("amount", "sum"),
average=("amount", "mean"),
)
print(summary)
# ✅ Expected output:
# region amount pct_of_region
# 0 N 30 30.0
# 1 N 70 70.0
# 2 S 40 40.0
# 3 S 60 60.0
# total average
# region
# N 100 50.0
# S 100 50.0❓ Frequently Asked Questions
Lesson complete — you summarise like a pro!
You can now run lists and dicts of functions with agg, give outputs clean names with named aggregation, and use transform to broadcast group statistics back onto every row. You know exactly when to reduce and when to preserve shape.
Practice quiz
What does .agg(['sum', 'mean', 'max']) on a grouped column return?
- One summary row per group with three result columns
- A single number
- The original rows unchanged
- An error
Answer: One summary row per group with three result columns. A list of functions produces one column per function, summarised per group.
How do you apply a different function to each column in one call?
- Pass a list of functions
- Pass a dictionary mapping column to function
- Call .agg() with no arguments
- Use .transform()
Answer: Pass a dictionary mapping column to function. A dict like {'points':'sum','minutes':'mean'} maps each column to its own function.
In named aggregation, what is the form of each keyword's value?
- A single function name
- A tuple of (column, function)
- A list of columns
- A boolean
Answer: A tuple of (column, function). Each keyword maps to a (source_column, function) tuple, and the keyword becomes the output column name.
What is the main difference between agg and transform?
- agg reduces each group to one row; transform keeps the original shape
- They are identical
- transform only works on numbers
- agg cannot use mean
Answer: agg reduces each group to one row; transform keeps the original shape. agg collapses each group to a summary; transform broadcasts a result back to every original row.
For df.groupby('team')['points'].transform('sum') with teams A,A,B,B,B and points 10,20,5,15,25, what is the result?
- [30, 45]
- [30, 30, 45, 45, 45]
- [10, 20, 5, 15, 25]
- [15, 15]
Answer: [30, 30, 45, 45, 45]. transform broadcasts each team's total (A=30, B=45) onto every row, keeping the original length.
Which method gives a smaller summary table rather than a column the same length as the DataFrame?
- transform
- agg
- map
- apply with axis=1
Answer: agg. agg reduces to a summary; use transform when you want a same-length column.
Why use named aggregation instead of a list of functions?
- It runs faster
- It avoids awkward MultiIndex column names by giving clean labels
- It is the only way to use sum
- It changes the index
Answer: It avoids awkward MultiIndex column names by giving clean labels. Named aggregation lets you set predictable, readable output column names directly.
To compute each row's share of its group total, which approach fits best?
- Divide the value by a transform('sum') of the group
- Use agg('sum') alone
- Use sort_values
- Use drop_duplicates
Answer: Divide the value by a transform('sum') of the group. transform('sum') keeps the same shape so you can divide each value by its group total.
What does .agg(games=('points', 'count')) produce for a group of 3 rows?
- The value 3 in a column named games
- The sum of points
- The mean of points
- An error because count needs a list
Answer: The value 3 in a column named games. count counts the rows in the group; the keyword games names the output column.
Which statement about transform is true?
- It returns fewer rows than the input
- It returns a value for every original row
- It only works after agg
- It removes duplicate groups
Answer: It returns a value for every original row. transform preserves shape, returning one value per original row.
Continue this course
- Previous: GroupBy: Split-Apply-Combine
- Next: Merging & Joining DataFrames — Combine datasets on keys with inner, left, right, and outer joins
- Quick reference: Pandas cheat sheet › Grouping & Aggregation
Frequently asked questions
What is the difference between agg and transform in pandas?
agg reduces each group to a single summary row, so a group of ten rows might become one mean value. transform keeps the original shape and broadcasts the group result back to every row, so you can compare each row against its group statistic.
How do I rename the output columns of a groupby aggregation?
Use named aggregation: pass keyword arguments to .agg where each name maps to a tuple of (column, function), for example .agg(total=('amount', 'sum')). The keyword becomes the output column name, giving you clean, predictable labels.
When should I use groupby().transform()?
Reach for transform when you need a per-group statistic attached to every original row, such as the group mean, a group share of total, or a within-group z-score. Because it preserves the row count, the result lines up perfectly for assignment back into the DataFrame.