agg() in Depth
Run several aggregates per group with agg(): a list of functions, a dict per column, named aggregation like agg(total=('runs', 'sum')), and custom functions.
Watch the lesson
1 video on CodeWithMunnaX
A single sum() per team is a good start, but a real team report needs several numbers at once: total runs, best score, number of players, total wickets… Calling groupby five times and joining the answers is clumsy. agg() (short for aggregate) computes any mix of aggregates in one call.
We continue with the squad from the previous topics (player, team, runs, wickets, matches).
Definition
agg()(aliasaggregate()) applies one or more aggregation functions to a Series, a DataFrame or a GroupBy object, where each function can be given as a name string, a callable, a list of these, or a dict that maps each column to its own function(s). On a GroupBy, every function runs once per group.
- Name string —
"sum","mean","median","min","max","count","std","nunique","first","last","size"… These are fast built-in implementations. - Callable — your own function (or
lambda) that receives a group's Series and returns one value. - List — run all functions on the selected column(s); the result gets one column per function.
- Dict — choose different functions for different columns.
Syntax
python
# 1. one function
df.groupby("team")["runs"].agg("sum")
# 2. list of functions
df.groupby("team")["runs"].agg(["sum", "mean", "max"])
# 3. dict: column -> function(s)
df.groupby("team").agg({"runs": "sum", "wickets": ["sum", "max"]})
# 4. named aggregation: new_column=(source_column, function)
df.groupby("team").agg(total_runs=("runs", "sum"), best=("runs", "max"))| Form | What you pass | Result columns |
|---|---|---|
| single | "sum" or a function | same shape as calling .sum() |
| list | ["sum", "max"] | one column per function (a 2-level MultiIndex if several input columns) |
| dict | {"runs": "sum", "wickets": "max"} | one column per (column, function) pair |
| named | new=("col", "func") keyword arguments | flat, custom-named columns — the cleanest |
pd.NamedAgg(column=..., aggfunc=...) | same as named, more explicit | flat, custom names |
Example — a list of functions
python
print(df.groupby("team")["runs"].agg(["sum", "mean", "max", "count"]))text
sum mean max count
team
CSK 441 220.500000 280 2
GT 890 890.000000 890 1
MI 1037 345.666667 605 3
RCB 1471 735.500000 741 2How it works: for each team, all four functions run on that team's runs. The function names become the column names.
If you select several columns with a list of functions, the columns become two-level (column, function):
python
r = df.groupby("team")[["runs", "wickets"]].agg(["sum", "max"])
print(r)
print(r.columns.tolist())text
runs wickets
sum max sum max
team
CSK 441 280 20 20
GT 890 890 0 0
MI 1037 605 20 20
RCB 1471 741 0 0
[('runs', 'sum'), ('runs', 'max'), ('wickets', 'sum'), ('wickets', 'max')]Access one of them with a tuple: r[("runs", "sum")]. These MultiIndex columns are powerful but awkward — which is why named aggregation exists.
Example — a dict: different functions per column
python
print(df.groupby("team").agg({"runs": "sum", "wickets": "max", "matches": "mean"}))text
runs wickets matches
team
CSK 441 20 15.000000
GT 890 0 17.000000
MI 1037 20 14.333333
RCB 1471 0 14.500000How it works: only the columns named in the dict are used (here player is ignored, so no TypeError). A value can also be a list: {"runs": ["sum", "max"], "wickets": "sum"} gives MultiIndex columns again.
Example — named aggregation (recommended)
python
summary = df.groupby("team").agg(
total_runs=("runs", "sum"),
best_score=("runs", "max"),
players=("player", "count"),
total_wkts=("wickets", "sum"),
)
print(summary)text
total_runs best_score players total_wkts
team
CSK 441 280 2 20
GT 890 890 1 0
MI 1037 605 3 20
RCB 1471 741 2 0How it works: each keyword argument is new_column_name=(source_column, function). You decide the output name, can use the same source column many times (runs twice), and get flat column names that are easy to sort, rename or export. pd.NamedAgg(column="runs", aggfunc="sum") is the long-form spelling of the same tuple.
On a single column (SeriesGroupBy) the keyword form is even shorter: df.groupby("team")["runs"].agg(total="sum", average="mean").
Example — custom functions and lambdas
python
def run_range(s):
return s.max() - s.min()
print(df.groupby("team")["runs"].agg(["min", "max", run_range]))text
min max run_range
team
CSK 161 280 119
GT 890 890 0
MI 15 605 590
RCB 730 741 11How it works: pandas calls run_range once per group, passing that group's runs Series; the function name becomes the column name. A lambda works too, especially inside named aggregation: span=("runs", lambda s: s.max() - s.min()). Custom Python functions are slower than built-in strings, so use a string whenever one exists.
Example — derived metrics after agg
python
bat = pd.DataFrame({
"team": ["MI", "MI", "CSK", "CSK", "RCB"],
"runs": [45, 80, 60, 20, 95],
"balls": [30, 50, 40, 25, 55],
})
t = bat.groupby("team").agg(runs=("runs", "sum"), balls=("balls", "sum"))
t["strike_rate"] = (t["runs"] / t["balls"] * 100).round(2)
print(t)text
runs balls strike_rate
team
CSK 80 65 123.08
MI 125 80 156.25
RCB 95 55 172.73How it works: a team strike rate must be computed from team totals (total runs ÷ total balls), not by averaging each batter's strike rate. Aggregate first, then derive.
agg() without groupby
agg also works on a plain DataFrame (notebook 08: df.agg(["max", "min", "count"])). With a dict, cells that were not requested become NaN:
python
print(df.agg({"runs": ["sum", "mean"], "wickets": "max"}))text
runs wickets
sum 3839.000 NaN
mean 479.875 NaN
max NaN 20.0Common mistakes
- ❌ Passing a column name that does not exist in a dict/named agg →
KeyError. ✅ Checkdf.columnsfirst. - ❌
agg(total=("runs", sum))using Python's built-insumunknowingly. ✅ Prefer the string"sum"— it is faster and NaN-aware. - ❌ A custom function that returns a list/Series instead of one value. ✅ An aggregation must return one scalar per group (use
transformorapplyotherwise). - ❌ Fighting MultiIndex columns from a list/dict agg. ✅ Use named aggregation for flat, readable column names.
- ❌ Averaging per-player ratios to get a team ratio. ✅ Aggregate the raw totals, then divide.
Interview tip
Q: How do you compute the sum of one column and the max of another per group, with custom output names?
A: Named aggregation: df.groupby("team").agg(total_runs=("runs", "sum"), best_wkts=("wickets", "max")). Each keyword is new_name=(column, function) and the result has flat column names.
Key points to remember
- agg() (alias aggregate()) runs one or many aggregation functions per group in a single call.
- A list of functions gives one column per function; on several columns it creates MultiIndex columns like ('runs', 'sum').
- A dict maps each column to its own function(s): agg({'runs': 'sum', 'wickets': 'max'}).
- Named aggregation agg(total=('runs', 'sum')) gives flat, custom column names — the recommended style.
- Custom functions and lambdas receive each group's Series and must return a single value.
- Built-in string names ('sum', 'mean', 'nunique') are faster than Python callables.
- Compute group ratios (like strike rate) from aggregated totals, not by averaging row-level ratios.
Try it yourself
List, dict and named aggregation
Custom functions and derived metrics
Practice: build a season report card
Revision Flashcards
Tap a card to flip it and see the answer.
