Group Data with groupby Aggregations

Learn to group data with groupby aggregations in this step-by-step tutorial — covering the core concept, hands-on exercises, and common edge cases.

Focus: group data with groupby aggregations

Sponsored

You've cleaned your data, filtered rows, and created new columns — but now the real questions begin. How do you compare sales across regions? What's the average revenue per product category? Aggregate functions alone can't answer these; you need to group data with groupby aggregations. This is the step where raw tables become actionable insights, and mastering it will transform you from a data wrangler into a data analyst.

The problem this lesson solves

Imagine you have a DataFrame with thousands of rows: sales transactions, customer reviews, or sensor readings. You need to answer questions like "What is the average order value per customer?" or "How many units were sold per product?"

If you try to filter and calculate each group manually, you'll write repetitive, error-prone code that doesn't scale. Even worse, you're missing the forest for the trees — you can't see patterns across groups when you're stuck inspecting individual rows.

Without grouping, your analysis is limited to whole-table stats — you can't compare segments or trends.

Groupby aggregations solve this by letting you split your data into logical groups, apply a function (like sum, mean, count) to each group, and then combine the results into a tidy summary. This is the classic split-apply-combine pattern, and it's the backbone of countless real-world analyses.

Core concept / mental model

Think of grouping data like sorting a deck of cards by suit and then summarizing each pile. You're not looking at every card; you're asking, "How many hearts are there? What's the average value of spades?"

In pandas, the groupby method implements this idea: - Split: The DataFrame is divided into groups based on one or more columns (your grouping keys). - Apply: An aggregation function (e.g., sum, mean, count, max) is computed within each group. - Combine: The results are assembled into a new DataFrame (or Series) with one row per group.

Key definitions: - Grouping key: The column(s) you use to divide the data. This can be a single column name or a list of columns. - Aggregation function: A statistical or summary operation that reduces multiple values into one — think total, average, or count. - Result: A new object where the grouping keys become the index (by default), and the aggregated columns are shown.

🧠 Pro tip: The result of a groupby is not a DataFrame — it's a special DataFrameGroupBy object. You must apply an aggregation method to get your summary table.

How it works step by step

Here's the typical flow for grouping data with groupby aggregations:

  1. Choose your grouping key(s): Decide which column(s) define your groups. For example, 'Region' to compare regions, or ['Year', 'Quarter'] for time-based groupings.
  2. Select the columns to aggregate: Sometimes you want all numeric columns; other times you specify just one or two.
  3. Pick your aggregation function: Common choices include sum, mean, count, min, max, median, std, and first. You can also use agg() to apply multiple functions at once.
  4. Call the method: Chain df.groupby('key')['col'].sum() or use df.groupby('key').agg({'col1': 'sum', 'col2': 'mean'}).
  5. Inspect and use the result: The output is a new DataFrame indexed by your group keys. You can reset_index() to turn it back into a normal column-based DataFrame for further analysis or plotting.

Why this order matters: Each step builds on the previous one. If you skip selecting columns, you'll aggregate all numeric columns, which may be noisy. If you forget to reset the index, you might accidentally treat the group keys as a row index in later steps.

Hands-on walkthrough

Let's put this into practice with a realistic sales dataset. Fire up your notebook and follow along.

import pandas as pd

# Sample sales data
df = pd.DataFrame({
    'Region': ['North', 'South', 'North', 'East', 'South', 'East', 'North', 'East'],
    'Product': ['A', 'A', 'B', 'A', 'B', 'B', 'A', 'A'],
    'Units': [10, 5, 8, 12, 7, 6, 9, 4],
    'Revenue': [1000, 700, 800, 1500, 900, 750, 1100, 500]
})

print(df)

Output:

  Region Product  Units  Revenue
0  North       A     10     1000
1  South       A      5      700
2  North       B      8      800
3   East       A     12     1500
4  South       B      7      900
5   East       B      6      750
6  North       A      9     1100
7   East       A      4      500

Example 1: Total revenue per region

# Group by Region, sum the Revenue column
revenue_by_region = df.groupby('Region')['Revenue'].sum()
print(revenue_by_region)

Output:

Region
East     2750
North    2900
South    1600
Name: Revenue, dtype: int64

Example 2: Multiple aggregations on the same column

What if you want both total units and average revenue per product? Use the agg() method:

# Group by Product, compute sum of Units and mean of Revenue
summary = df.groupby('Product').agg({'Units': 'sum', 'Revenue': 'mean'})
print(summary)

Output:

        Units  Revenue
Product               
A          40   950.0
B          21   816.7

Example 3: Aggregating multiple columns differently

Need a more complex report? Group by Region, then get total units and average revenue per region:

region_stats = df.groupby('Region').agg({
    'Units': 'sum',
    'Revenue': 'mean'
})
print(region_stats)

Output:

        Units  Revenue
Region               
East       22    916.7
North      27    966.7
South      12    800.0

Example 4: Resetting the index for further use

Often you want the group keys as regular columns, not the index. Use reset_index():

region_stats_reset = df.groupby('Region', as_index=False)['Revenue'].sum()
print(region_stats_reset)

Output:

  Region  Revenue
0   East     2750
1  North     2900
2  South     1600

Alternatively, you can call reset_index() on the grouped result:

region_stats = df.groupby('Region')['Revenue'].sum().reset_index()

🧠 Pro tip: Use as_index=False in groupby to keep your grouping columns as regular columns right away — this often saves a step and prevents index-related surprises.

Compare options / when to choose what

There are several ways to aggregate after grouping, and each fits a different need:

Method Best for Example
Direct method (.sum(), .mean()) A single aggregation on one or all numeric columns df.groupby('Region')['Revenue'].sum()
agg() with a dict Different functions per column df.groupby('Region').agg({'Units': 'sum', 'Revenue': 'mean'})
agg() with a list Multiple functions on the same column df.groupby('Product')['Revenue'].agg(['sum', 'mean'])
pivot_table Nice presentation with multi-level rows/columns pd.pivot_table(df, values='Revenue', index='Region', aggfunc='sum')

When to choose what: - For quick, single summaries, use direct methods like sum() or mean(). - When you need different calculations on different columns, agg() with a dictionary is your friend. - If you want multiple statistics (e.g., total and average) on the same column, pass a list to agg(). - For a more structured, spreadsheet-like output (especially with two grouping keys), consider pivot_table.

Troubleshooting & edge cases

  1. KeyError when column name is wrong or missing - Double-check column names with df.columns. Typos are the most common cause.

  2. Groupby with categorical data yields empty groups - If your grouping column is category, groups that have no rows still appear with NaN or 0. Use observed=True in groupby to include only observed categories.

  3. Aggregating non-numeric columns throws an error - Functions like sum() expect numeric data. Either select numeric columns explicitly or use a function that works on strings (e.g., first, count).

  4. Result index becomes the group key(s) unexpectedly - If you later try to merge or compare using column names, remember to reset_index() or use as_index=False.

  5. NaN values in grouping columns - By default, pandas drops rows with NA in the grouping key. If you need to keep them, use dropna=False in groupby.

What you learned & what's next

You've just unlocked the power of group data with groupby aggregations. You now understand the split-apply-combine pattern, can write foundational groupby calls, apply multiple aggregations, and avoid common pitfalls. These skills are essential for summarizing data fast and derive insights from your datasets.

In the next lesson, you'll dive into merging and joining datasets — combining multiple DataFrames into a single, richer table for even deeper analysis. With grouping and merging together, you'll be able to build complex, real-world analytical pipelines.

Keep practicing! Open any DataFrame, group by a meaningful column, and ask a question your data can answer. The more you experiment, the more natural these patterns will feel.

Practice recap

As a mini exercise, load a dataset of your choice (e.g., the built-in tips dataset from seaborn) and group by a categorical column like 'day' or 'sex'. Compute the average total_bill per group and then add the count of rows per group using agg(). Finally, reset the index and print the resulting DataFrame to see what you've built.

Common mistakes

  • Forgetting to select a column before applying an aggregation (e.g., df.groupby('Region').sum()) — this aggregates all numeric columns, which may produce noisy or unintended results.
  • Expecting the grouped result to have group keys as columns — by default they become the index. Use as_index=False or reset_index() to keep them as columns.
  • Trying to call groupby.agg() without specifying column names when you need different functions per column — ensure your dictionary keys match existing column names exactly.
  • Ignoring NaN values in grouping columns, which are dropped by default — use dropna=False if you need to keep them.

Variations

  1. Use pivot_table for a more spreadsheet-like output, especially when you have two grouping keys: pd.pivot_table(df, values='Revenue', index='Region', columns='Product', aggfunc='sum').
  2. Apply multiple aggregation functions to the same column using a list: df.groupby('Product')['Revenue'].agg(['sum', 'mean', 'count']).
  3. For time-series data, use pd.Grouper with a frequency (e.g., 'M' for monthly) to group by date ranges: df.groupby(pd.Grouper(key='Date', freq='M')).sum().

Real-world use cases

  • E-commerce: Calculate total sales and average order value per product category to guide inventory restocking decisions.
  • Finance: Compute monthly total expenses and average transaction amount per spending category from a credit card statement.
  • Operations: Analyze average response time and total tickets closed per support team member to optimize workload distribution.

Key takeaways

  • The split-apply-combine pattern is the core of groupby aggregations: split data by keys, apply functions, and combine results.
  • Use df.groupby('key')['col'].func() for a quick, single aggregation on one column.
  • The agg() method lets you apply different aggregation functions to multiple columns in one call.
  • Group keys become the index of the result by default — use as_index=False or reset_index() to keep them as columns.
  • Handle edge cases: empty categories, NaN grouping keys, and non-numeric columns to avoid errors.
  • Mastering groupby aggregations is a stepping stone to more advanced analyses like merging and joining datasets.

Sponsored

Sponsored