Mathew K Analytics

Lesson 9 · Python for Retail E-commerce Analytics

Introduction to Pandas for Retail Analytics Using Python

In this lesson, we will learn how to use Python and Pandas to analyze real-world retail and e-commerce transaction data. You will see why retail analytics…

⬇ Download notebookOpen in Colab ↗

📓 Full notebook

Download .ipynb

Introduction to Pandas for Retail Analytics#

  • In this lesson, we will learn how to use Python and Pandas to analyze real-world retail and e-commerce transaction data.
  • You will see why retail analytics is critical for sales, marketing, and inventory decisions.
  • By practicing with real retail datasets, you will discover how to generate insights such as revenue trends, top-selling products, and customer purchasing behaviors.
  • This knowledge helps make smarter data-driven decisions in retail businesses.
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings('ignore')

Core concepts in Pandas for retail analytics#

  • Most retail datasets contain information about transactions, orders, products, and customers.
  • Columns may include invoice or order numbers, product codes, descriptions, quantities, prices, and customer identifiers.
  • Sales metrics are typically calculated as quantity multiplied by price for each transaction.
  • Beginners often make mistakes such as grouping by the wrong column, calculating sums instead of averages, or misinterpreting revenue versus quantity.
# Load a real retail transactions dataset from UCI
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/00502/online_retail_II.xlsx'
df = pd.read_excel(url, sheet_name='Year 2010-2011')
df['InvoiceDate'] = pd.to_datetime(df['InvoiceDate'])
print(df.shape)
print(df.head(3))
(541910, 8)
  Invoice StockCode                         Description  Quantity  \
0  536365    85123A  WHITE HANGING HEART T-LIGHT HOLDER         6   
1  536365     71053                 WHITE METAL LANTERN         6   
2  536365    84406B      CREAM CUPID HEARTS COAT HANGER         8   

          InvoiceDate  Price  Customer ID         Country  
0 2010-12-01 08:26:00   2.55      17850.0  United Kingdom  
1 2010-12-01 08:26:00   3.39      17850.0  United Kingdom  
2 2010-12-01 08:26:00   2.75      17850.0  United Kingdom  

Beginner Example 1: Count total transactions#

  • One of the first steps in retail analytics is understanding how busy your store is.
  • We will count the total number of retail transactions.
total_transactions = df['Invoice'].nunique()
print(f'Total unique retail transactions: {total_transactions}')
Total unique retail transactions: 25900

Beginner Example 2: Calculate total revenue#

  • Revenue is a key performance metric for any store.
  • We will calculate the total revenue (income) by multiplying quantity and price for each transaction.
df['Revenue'] = df['Quantity'] * df['Price']
total_revenue = df['Revenue'].sum()
print(f'Total revenue for this period: {total_revenue:.2f}')
Total revenue for this period: 9747765.93

Beginner Example 3: Identify top-selling product#

  • Knowing which products sell the most helps with inventory planning.
  • We will find the product with the highest total quantity sold.
top_product = df.groupby('Description')['Quantity'].sum().sort_values(ascending=False).head(1)
print('Top selling product (by quantity):')
print(top_product)
Top selling product (by quantity):
Description
WORLD WAR 2 GLIDERS ASSTD DESIGNS    53847
Name: Quantity, dtype: int64

Intermediate Example 1: Average order value (AOV)#

  • Average order value shows how much customers usually spend per transaction.
  • This helps identify up-sell or cross-sell opportunities.
order_revenue = df.groupby('Invoice')['Revenue'].sum()
aov = order_revenue.mean()
print(f'Average order value: {aov:.2f}')
Average order value: 376.36

Intermediate Example 2: Sales by country#

  • Analyzing sales by country uncovers international opportunities.
  • Let us find which country generates the most revenue.
country_revenue = df.groupby('Country')['Revenue'].sum().sort_values(ascending=False)
print('Top 5 countries by total revenue:')
print(country_revenue.head(5))
Top 5 countries by total revenue:
Country
United Kingdom    8187806.364
Netherlands        284661.540
EIRE               263276.820
Germany            221698.210
France             197421.900
Name: Revenue, dtype: float64

Intermediate Example 3: Monthly sales trends#

  • Understanding sales trends over time helps with marketing and inventory planning.
  • We will compute monthly revenue to identify trends.
df['Month'] = df['InvoiceDate'].dt.to_period('M')
monthly_sales = df.groupby('Month')['Revenue'].sum()
print('Monthly revenue:')
print(monthly_sales.head())
Monthly revenue:
Month
2010-12    748957.020
2011-01    560000.260
2011-02    498062.650
2011-03    683267.080
2011-04    493207.121
Freq: M, Name: Revenue, dtype: float64

Advanced Example 1: Customer lifetime value (CLV)#

  • Customer lifetime value helps businesses focus on the most profitable customers.
  • Let us estimate CLV by summing up revenue for each customer.
clv = df.groupby('Customer ID')['Revenue'].sum().sort_values(ascending=False).head(5)
print('Top 5 customers by lifetime revenue:')
print(clv)
Top 5 customers by lifetime revenue:
Customer ID
14646.0    279489.02
18102.0    256438.49
17450.0    187482.17
14911.0    132572.62
12415.0    123725.45
Name: Revenue, dtype: float64

Advanced Example 2: Product category analysis (using a simulated catalog)#

  • Product categories help businesses spot trends and gaps in their assortment.
  • We will build a simulated product catalog dataset and join it with transaction data.
np.random.seed(42)
categories = ['Electronics','Clothing','Home','Sports','Beauty']
product_ids = list(df['StockCode'].unique())[:100]
assigned_categories = np.random.choice(categories, len(product_ids))
catalog = pd.DataFrame({'StockCode': product_ids, 'Category': assigned_categories})
df_merged = pd.merge(df, catalog, on='StockCode', how='left')
cat_sales = df_merged.groupby('Category')['Revenue'].sum()
print('Total revenue by category:')
print(cat_sales)
Total revenue by category:
Category
Beauty         208348.42
Clothing       411712.48
Electronics    226440.06
Home           172785.79
Sports         356849.12
Name: Revenue, dtype: float64

Advanced Example 3: Time-based cohort analysis#

  • Cohort analysis groups new customers by when they first purchased, revealing retention or repeat patterns.
  • Let us estimate the first purchase month for each customer and analyze total sales by cohort.
df['FirstPurchaseMonth'] = df.groupby('Customer ID')['InvoiceDate'].transform('min').dt.to_period('M')
cohort_sales = df.groupby('FirstPurchaseMonth')['Revenue'].sum()
print('Cohort-based monthly sales:')
print(cohort_sales.head())
Cohort-based monthly sales:
FirstPurchaseMonth
2010-12    4409023.950
2011-01    1001324.581
2011-02     550117.190
2011-03     594335.570
2011-04     321570.861
Freq: M, Name: Revenue, dtype: float64

Error handling: Missing values in retail data#

  • Missing values are common in large transaction datasets and can cause problems.
  • We will check for and visualize missing values.
missing_counts = df.isnull().sum()
print('Missing value count per column:')
print(missing_counts)
Missing value count per column:
Invoice                    0
StockCode                  0
Description             1454
Quantity                   0
InvoiceDate                0
Price                      0
Customer ID           135080
Country                    0
Revenue                    0
Month                      0
FirstPurchaseMonth    135080
dtype: int64

Error handling: Preventing incorrect groupings#

  • Grouping by the wrong column can produce inaccurate sales numbers.
  • Let us demonstrate what happens if we aggregate revenue per product without deduplication.
invalid_revenue = df.groupby('StockCode')['Revenue'].mean().head(3)
print('Incorrect average revenue per product (should use sums, not means!):')
print(invalid_revenue)
Incorrect average revenue per product (should use sums, not means!):
StockCode
10002    10.409452
10080     4.962083
10120     1.351000
Name: Revenue, dtype: float64

Error handling: Fixing revenue calculations#

  • It is important to sum revenue at the correct grouping level.
  • We will correct our earlier mistake by summing instead of averaging.
correct_revenue = df.groupby('StockCode')['Revenue'].sum().head(3)
print('Correct total revenue per product:')
print(correct_revenue)
Correct total revenue per product:
StockCode
10002    759.89
10080    119.09
10120     40.53
Name: Revenue, dtype: float64

Retail analytics best practices#

  • Segment customers based on spend or frequency to focus on high-value groups.
  • Review product performance regularly to optimize the assortment.
  • Use basket analysis to discover commonly bought-together products.
  • Study demand and seasonality to anticipate inventory needs.
# Customer segmentation example: Label high spenders
high_spenders = df.groupby('Customer ID')['Revenue'].sum()
high_spender_flags = high_spenders > high_spenders.quantile(0.9)
print(f'Number of high-value customers: {high_spender_flags.sum()}')
Number of high-value customers: 438
# Product performance: Top category products
top_cat = df_merged.groupby(['Category','Description'])['Revenue'].sum()
top_cat_sorted = top_cat.sort_values(ascending=False).head(5)
print('Top 5 products by revenue within their category:')
print(top_cat_sorted)
Top 5 products by revenue within their category:
Category     Description                       
Sports       WHITE HANGING HEART T-LIGHT HOLDER    97715.99
Electronics  POSTAGE                               66248.64
Clothing     PAPER CHAIN KIT 50'S CHRISTMAS        63791.94
             ASSORTED COLOUR BIRD ORNAMENT         58959.73
             JUMBO BAG PINK POLKADOT               41619.66
Name: Revenue, dtype: float64
# Market basket analysis setup: Simulate market basket transactions
np.random.seed(42)
products = ['Bread','Milk','Butter','Eggs','Apples','Chicken','Rice','Cheese']
transaction_ids = np.repeat(np.arange(1,301),3)
product_choices = np.random.choice(products,len(transaction_ids))
mb_df = pd.DataFrame({'TransactionID':transaction_ids,'Product':product_choices})
print(mb_df.head(3))
   TransactionID Product
0              1    Rice
1              1    Eggs
2              1  Apples
# Demand forecasting: Simple time-series sales summarization
daily_sales = df.groupby(df['InvoiceDate'].dt.date)['Revenue'].sum()
print(daily_sales.head())
InvoiceDate
2010-12-01    58635.56
2010-12-02    46207.28
2010-12-03    45620.46
2010-12-05    31383.95
2010-12-06    53860.18
Name: Revenue, dtype: float64

End-to-end mini problem: Find top-selling products & recommend inventory action#

  • Let us put it all together by identifying the top five products by revenue.
  • Based on the result, suggest a business or inventory recommendation.
top5_revenue = df.groupby('Description')['Revenue'].sum().sort_values(ascending=False).head(5)
print('Top 5 products by total revenue:')
print(top5_revenue)

# Business recommendation based on top sellers
if top5_revenue.iloc[0] > top5_revenue.mean() * 2:
    print('Recommendation: Increase inventory and promotion for the best-selling product.')
else:
    print('Recommendation: Diversify assortment or cross-sell to boost more products.')
Top 5 products by total revenue:
Description
DOTCOM POSTAGE                        206245.48
REGENCY CAKESTAND 3 TIER              164762.19
WHITE HANGING HEART T-LIGHT HOLDER     99668.47
PARTY BUNTING                          98302.98
JUMBO BAG RED RETROSPOT                92356.03
Name: Revenue, dtype: float64
Recommendation: Diversify assortment or cross-sell to boost more products.
 

Found this useful?

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