Mathew K Analytics

Lesson 10 · Data analytics zero to hero

Pandas GroupBy & Aggregation Made Simple | Data Analytics #10

Video ten of the 30-part series, a deep dive into groupby: the single most important tool for turning raw rows into a real summary. We're continuing with…

What you'll learn

Datasets used in this lesson

Save these next to the notebook. In Google Colab, upload them with the 📁 icon on the left first.

📓 Full notebook

Download .ipynb

Data Analytics Zero to Hero, Video 10: GroupBy and Aggregation#

  • Video ten of the 30-part series, a deep dive into groupby: the single most important tool for turning raw rows into a real summary.
  • We're continuing with the real, cleaned Online Retail extract.
  • Let's jump straight in.

Before You Start#

  • Open a new Jupyter Notebook in VS Code and select your Python interpreter as the kernel.
  • Place online_retail_sample.csv in the same folder as this notebook.
import pandas as pd

df = pd.read_csv('online_retail_sample.csv')
df = df.dropna(subset=['CustomerID']).drop_duplicates()
df = df[(df['Quantity'] > 0) & (df['UnitPrice'] > 0)]
df['TotalPrice'] = df['Quantity'] * df['UnitPrice']
print(df.shape)
(1394, 9)

Part 1: Basic groupby#

by_country = df.groupby('Country')
print(type(by_country))
print(by_country['TotalPrice'].sum())
<class 'pandas.core.groupby.generic.DataFrameGroupBy'>
Country
Australia           358.25
EIRE                555.38
France              855.86
Germany             261.48
Netherlands         192.60
Norway             1919.14
United Kingdom    28259.30
Name: TotalPrice, dtype: float64
revenue_by_country = df.groupby('Country')['TotalPrice'].sum().sort_values(ascending=False)
print(revenue_by_country.head(5))
Country
United Kingdom    28259.30
Norway             1919.14
France              855.86
EIRE                555.38
Australia           358.25
Name: TotalPrice, dtype: float64

Part 2: Multiple Aggregations with agg#

summary = df.groupby('Country')['TotalPrice'].agg(['sum', 'mean', 'count'])
print(summary.head(5))
                sum       mean  count
Country                              
Australia    358.25  25.589286     14
EIRE         555.38  26.446667     21
France       855.86  42.793000     20
Germany      261.48  17.432000     15
Netherlands  192.60  96.300000      2
named = df.groupby('Country').agg(
    total_revenue=('TotalPrice', 'sum'),
    avg_order_value=('TotalPrice', 'mean'),
    num_orders=('InvoiceNo', 'nunique')
)
print(named.sort_values('total_revenue', ascending=False).head(5))
                total_revenue  avg_order_value  num_orders
Country                                                   
United Kingdom       28259.30        22.625540          76
Norway                1919.14        26.289589           1
France                 855.86        42.793000           1
EIRE                   555.38        26.446667           2
Australia              358.25        25.589286           1

Part 3: Grouping by Multiple Columns#

df['InvoiceDate'] = pd.to_datetime(df['InvoiceDate'])
df['Month'] = df['InvoiceDate'].dt.to_period('M')
monthly_country = df.groupby(['Month', 'Country'])['TotalPrice'].sum()
print(monthly_country.head(6))
Month    Country    
2010-12  Australia       358.25
         EIRE            555.38
         France          855.86
         Germany         261.48
         Netherlands     192.60
         Norway         1919.14
Name: TotalPrice, dtype: float64
print(monthly_country.unstack().fillna(0).round(2))
Country  Australia    EIRE  France  Germany  Netherlands   Norway  \
Month                                                               
2010-12     358.25  555.38  855.86   261.48        192.6  1919.14   

Country  United Kingdom  
Month                    
2010-12         28259.3  

Part 4: transform#

df['CountryAvgOrder'] = df.groupby('Country')['TotalPrice'].transform('mean')
print(df[['Country', 'TotalPrice', 'CountryAvgOrder']].head(5))
          Country  TotalPrice  CountryAvgOrder
0  United Kingdom       15.30         22.62554
1  United Kingdom       20.34         22.62554
2  United Kingdom       22.00         22.62554
3  United Kingdom       20.34         22.62554
4  United Kingdom       20.34         22.62554
df['AboveCountryAvg'] = df['TotalPrice'] > df['CountryAvgOrder']
print(df['AboveCountryAvg'].value_counts())
AboveCountryAvg
False    1069
True      325
Name: count, dtype: int64

Part 5: pivot_table and crosstab#

pivot = df.pivot_table(values='TotalPrice', index='Month', columns='Country', aggfunc='sum', fill_value=0)
print(pivot.round(2))
Country  Australia    EIRE  France  Germany  Netherlands   Norway  \
Month                                                               
2010-12     358.25  555.38  855.86   261.48        192.6  1919.14   

Country  United Kingdom  
Month                    
2010-12         28259.3  
top_countries = revenue_by_country.head(4).index
subset = df[df['Country'].isin(top_countries)]
ct = pd.crosstab(subset['Country'], subset['Month'])
print(ct)
Month           2010-12
Country                
EIRE                 21
France               20
Norway               73
United Kingdom     1249

Wrap-Up: What You Learned#

  • groupby splits data into groups; nothing computes until you aggregate.
  • Multiple aggregations at once with agg, including named aggregation for clean output columns.
  • Grouping by multiple columns, and reshaping the multi-level result with unstack.
  • transform, for broadcasting a group statistic back to every original row.
  • pivot_table and crosstab, for spreadsheet-style summaries and combination counts.
  • All of it run against the same real, cleaned retail data. Video eleven covers merging, joining, and reshaping combining multiple real tables together, which is exactly what most real analyses actually require. Subscribe so it lands automatically see you there.

Found this useful?

All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.