Apply one or more aggregation functions at once, overall or per group.
agg is what you reach for when sum() alone is not enough — when you want the total and the count and the largest, each in its own column, computed in a single pass. It is also how you give those columns names you chose rather than names Pandas invented.
Official documentation: DataFrame.agg
The forms worth knowing
The one to learn first is named aggregation — each keyword becomes a column name, and each value is a (column, function) pair:
df.groupby('Region').agg(
units=('Capacity (MW)', 'size'),
total_mw=('Capacity (MW)', 'sum'),
biggest=('Capacity (MW)', 'max'),
)
The older forms still work and you will meet them in other people's code:
df.groupby('Region').agg(['sum', 'mean']) # every numeric column, both functions
df.groupby('Region').agg({'Capacity (MW)': 'sum'}) # per-column dict
df.agg({'Capacity (MW)': ['sum', 'max']}) # no groupby: whole-frame summary
Named aggregation is worth preferring because it produces flat, readable column names. The list and dict forms give you a MultiIndex on the columns, which then needs flattening before you can do anything else with it.
You can pass your own function too — agg(shortest=('Start year', lambda s: s.min())) — though a built-in string like 'min' runs in optimized code and is much faster.
A worked example, on real data
The Global Coal Plant Tracker lists every coal-fired generating unit on earth, one row per unit. Bamboo Weekly #64 used this dataset.
One question, four answers, one pass over the data:
import pandas as pd
url = ('https://www.bambooweekly.com/content/files/wp-content/uploads/2024/02/'
'global-coal-plant-tracker-january-2024.xlsx')
(
pd.read_excel(url, sheet_name='Units',
usecols=['Region', 'Capacity (MW)', 'Start year'])
.groupby('Region')
.agg(units=('Capacity (MW)', 'size'),
total_mw=('Capacity (MW)', 'sum'),
biggest=('Capacity (MW)', 'max'),
oldest=('Start year', 'min'))
)
Which gives:
units total_mw biggest oldest
Region
Africa 431 149016.6 1980.0 1952.0
Americas 1466 457503.9 2000.0 1935.0
Asia 10129 4020051.4 6300.0 1939.0
Europe 1740 428795.9 3000.0 1927.0
Oceania 140 46937.0 2000.0 1958.0
Note that oldest aggregates a different column from the other three — named aggregation lets each output column choose its own input. Asia has more than five times the units of any other region, and the oldest plant still running anywhere dates to 1927.
Three mistakes people make
Reaching for apply when agg will do. .apply hands your function an entire sub-frame and runs in Python; .agg with a built-in name like 'sum' runs in optimized code. For standard reductions the difference is large and free.
Using the list or dict form and then fighting the column names. agg(['sum','mean']) returns a MultiIndex on the columns, so you end up writing df[('Capacity (MW)','sum')] or flattening by hand. Named aggregation avoids the problem rather than solving it.
Forgetting that size and count differ. size counts rows in the group; count counts non-missing values in a column. When there are gaps in your data these give different answers, and only one of them is the one you meant.
Watch it
Five Pandas "groupby" mistakes to avoid covers several aggregation traps, since agg and groupby almost always travel together.
Practice it
Work through an agg exercise, with instant feedback and no signup required: practice.lernerpython.com/bamboo-weekly/agg/
Go deeper
Bamboo Weekly is the practice. If you want the structured version — full courses with downloadable Jupyter notebooks, plus live Pandas office hours when you get stuck — that is LernerPython+Data. A paid Bamboo Weekly subscription is included with it.
See it on real data
Below are the 60 Bamboo Weekly exercises that use agg on real-world data — try each one, then study the worked solution.
- Bamboo Weekly #181: Housing costs
- Bamboo Weekly #180: Movies
- Bamboo Weekly #177: European Summer
- Bamboo Weekly #176: Religious restrictions
- Bamboo Weekly #175: Inflation
- Bamboo Weekly #167: Oil prices
- Bamboo Weekly #157: Government corruption
- Bamboo Weekly #156: Winter Olympics
- Bamboo Weekly #153: Venezuela
- Bamboo Weekly #152: Congestion pricing
- Bamboo Weekly #151: PyPI in 2025
- Bamboo Weekly #148: US Manufacturing
- Bamboo Weekly #146: Thanksgiving travel
- Bamboo Weekly #144: Museum Heists
- Bamboo Weekly #142: Hurricanes
- Bamboo Weekly #141: Argentina
- Bamboo Weekly #138: Federal workers
- Bamboo Weekly #135: Airline seats
- Bamboo Weekly #130: Jobs reporting
- Bamboo Weekly #127: European comparisons
- Bamboo Weekly #126: EV sales
- Bamboo Weekly #125: Shrinking dollars
- Bamboo Weekly #119: Python conferences
- Bamboo Weekly #116: Philadelphia Fed survey
- Bamboo Weekly #111: State taxes
- Bamboo Weekly #106: Flu season
- Bamboo Weekly #105: Federal employees
- Bamboo Weekly #103: CDC data
- Bamboo Weekly #100: Sports betting
- Bamboo Weekly #99: Literacy and numeracy
- Bamboo Weekly #98: Retail sales
- Bamboo Weekly #89: Housing
- Bamboo Weekly #88: Hot summers
- Bamboo Weekly #84: Central banks
- Bamboo Weekly #81: School
- Bamboo Weekly #80: Inflation
- Bamboo Weekly #78: Stock markets
- Bamboo Weekly #76: Aging legislators
- Bamboo Weekly #73: Avocado hand
- Bamboo Weekly #72: City travel
- Bamboo Weekly #69: Election participation
- Bamboo Weekly #65: Microplastics
- Bamboo Weekly #57: International arms trade
- Bamboo Weekly #55: IVF
- Bamboo Weekly #53: Airport animals
- Bamboo Weekly #51: Academy Awards
- Bamboo Weekly #50: Red Sea shipping
- Bamboo Weekly #49: Campaign finance
- Bamboo Weekly #45: Netflix
- Bamboo Weekly #40: Sovereign Bonds
- Bamboo Weekly #37: Consumer finances
- Bamboo Weekly #36: Nobel Prize
- Bamboo Weekly #33: Fracking
- Bamboo Weekly #31: Poverty
- Bamboo Weekly #28: Pret a Manger
- Bamboo Weekly #24: Wildfire smoke
- Bamboo Weekly #10: Oil prices
- Bamboo Weekly #9: US house prices
- Bamboo Weekly #8: Happiness
- Bamboo Weekly #7: Bank failures
Part of the Pandas Methods Index. See also practice by skill.