Mathew K Analytics

Lesson 51 · Python for Retail E-commerce Analytics

Turning Retail Data into Business Insights with Python Analytics

In this lesson, we solve real-world retail analytics problems with Python. We learn how to analyze raw retail transaction data to extract business insights.…

⬇ Download notebookOpen in Colab ↗

📓 Full notebook

Download .ipynb

Turning Retail Data into Business Insights#

  • In this lesson, we solve real-world retail analytics problems with Python.
  • We learn how to analyze raw retail transaction data to extract business insights.
  • Understanding sales and customer trends helps make decisions for marketing, sales, and inventory.
  • You will learn to transform retail data into metrics that inform your retail strategy.
  • By the end, you will be able to find actionable insights like top-selling products and customer segments.
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings('ignore')

What Is Retail Data? Core Concepts#

  • Retail data covers transactions, orders, customers, and products.
  • Every transaction records product, customer, price, and date.
  • Sales metrics include revenue, quantity sold, and price per item.
  • Mistakes include double counting, not handling missing data, or misinterpreting groupings.
  • Accurate analysis starts with knowing what each dataset column represents.
# Load real online retail data (UCI repository)
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  

Example 1: Basic Sales Aggregation#

  • One of the first business questions: what is total sales revenue?
  • Sales revenue helps track overall performance over time.
  • Correctly handling missing or invalid data is important.
# Calculate total sales revenue
df['Sales'] = df['Quantity'] * df['Price']
total_sales = df['Sales'].sum()
print('Total sales revenue:', total_sales)
Total sales revenue: 9747765.934

Example 2: Top Selling Products#

  • Identifying top products guides what is stocked and promoted.
  • Group sales by product and sort to find the leaders.
  • This helps answer questions like, "Which products drive our revenue?"
# Aggregate sales by product description
product_sales = df.groupby('Description')['Sales'].sum()
top_products = product_sales.sort_values(ascending=False).head(5)
print('Top 5 products by sales:')
print(top_products)
Top 5 products by sales:
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: Sales, dtype: float64

Example 3: Sales Over Time#

  • Time-based analysis reveals growth or seasonality trends.
  • Grouping sales revenue by month or week gives management a bigger picture.
  • Such trends help plan marketing and inventory.
# Calculate monthly sales
df['Month'] = df['InvoiceDate'].dt.to_period('M')
monthly_sales = df.groupby('Month')['Sales'].sum()
print('Monthly sales totals:')
print(monthly_sales.head(6))
Monthly sales totals:
Month
2010-12    748957.020
2011-01    560000.260
2011-02    498062.650
2011-03    683267.080
2011-04    493207.121
2011-05    723333.510
Freq: M, Name: Sales, dtype: float64

Example 4: Customer-Level Sales (Intermediate)#

  • Knowing who buys the most helps target loyalty efforts.
  • We can group and rank customers by their total spend.
  • This insight is vital for customer retention strategies.
# Calculate total sales by customer
customer_sales = df.groupby('Customer ID')['Sales'].sum().sort_values(ascending=False)
print('Top 5 customers by sales:')
print(customer_sales.head(5))
Top 5 customers by sales:
Customer ID
14646.0    279489.02
18102.0    256438.49
17450.0    187482.17
14911.0    132572.62
12415.0    123725.45
Name: Sales, dtype: float64

Example 5: Product Category Performance (Intermediate)#

  • Products grouped by category reveal which segments drive revenue.
  • If category is missing, this is a good reason to link with product catalogs.
  • We will synthesize a product catalog and join it in later examples.
# Simulate a product catalog dataset and merge it with sales data
np.random.seed(42)
categories = ['Electronics','Clothing','Home','Sports','Beauty']
product_ids = df['StockCode'].unique()[:100]
product_categories = np.random.choice(categories, len(product_ids))
product_prices = np.round(np.random.uniform(5, 500, len(product_ids)), 2)
catalog = pd.DataFrame({'StockCode': product_ids, 'Category': product_categories, 'CatalogPrice': product_prices})
df_cat = pd.merge(df, catalog, on='StockCode', how='left')
category_sales = df_cat.groupby('Category')['Sales'].sum().sort_values(ascending=False)
print('Sales by category:')
print(category_sales)
Sales by category:
Category
Clothing       411712.48
Sports         356849.12
Electronics    226440.06
Beauty         208348.42
Home           172785.79
Name: Sales, dtype: float64

Example 6: Average Order Value (Intermediate)#

  • Average order value shows what a typical customer spends per order.
  • It is calculated as total sales divided by the number of orders.
  • Businesses track this metric to measure growth and impact of promotions.
# Calculate average order value (AOV)
order_sales = df.groupby('Invoice')['Sales'].sum()
aov = order_sales.mean()
print('Average order value:', round(aov,2))
Average order value: 376.36

Example 7: Time-Based Revenue Segmentation (Advanced)#

  • Segmenting revenue by time windows finds seasonality or fast growth.
  • Knowing monthly and weekday patterns is key for campaign planning.
  • We extract month and day info to dig deeper into sales cycles.
# Group sales by day of week
df['Weekday'] = df['InvoiceDate'].dt.day_name()
weekday_sales = df.groupby('Weekday')['Sales'].sum().sort_values(ascending=False)
print('Sales by day of week:')
print(weekday_sales)
Sales by day of week:
Weekday
Thursday     2112519.000
Tuesday      1966182.791
Wednesday    1734147.010
Monday       1588609.431
Friday       1540628.811
Sunday        805678.891
Name: Sales, dtype: float64

Example 8: Identifying Returned (Cancelled) Orders (Advanced)#

  • Returns and cancelled orders are a key performance metric.
  • In this dataset, negative quantities or 'C' in invoice names signal returns.
  • Understanding returns helps improve customer satisfaction and inventory forecasting.
# Flag and analyze returned orders
df['IsReturn'] = df['Invoice'].astype(str).str.startswith('C')
returns = df[df['IsReturn']]
return_sales = returns['Sales'].sum()
print('Total value of returned orders:', return_sales)
Total value of returned orders: -896812.49

Error Handling: Missing Values#

  • Not all transactions have price or customer info.
  • Missing data leads to wrong sales numbers or lost insights.
  • Spotting missing data is the first step to fixing it.
# Check for missing values in key columns
missing = df[['Quantity','Price','Customer ID']].isnull().sum()
print('Missing values in each column:')
print(missing)
Missing values in each column:
Quantity            0
Price               0
Customer ID    135080
dtype: int64

Error Handling: Aggregation and Grouping Errors#

  • Grouping by the wrong column can double-count or hide sales.
  • Aggregated metrics should always be checked and explained.
  • Business logic should match how the data is being grouped.
# Example: Incorrect grouping (Demo only)
sales_by_date = df.groupby('InvoiceDate')['Sales'].sum().head()
print('Sales summed by invoice datetime:')
print(sales_by_date)
Sales summed by invoice datetime:
InvoiceDate
2010-12-01 08:26:00    139.12
2010-12-01 08:28:00     22.20
2010-12-01 08:34:00    348.78
2010-12-01 08:35:00     17.85
2010-12-01 08:45:00    855.86
Name: Sales, dtype: float64

Best Practices: Customer Segmentation#

  • Segmentation finds groups of customers by spend or frequency.
  • Retailers use this to design personalized marketing and service.
  • Typical segments: new, repeat, VIP, at-risk customers.
# Simple RFM-style segmentation
last_date = df['InvoiceDate'].max()
rfm = df.groupby('Customer ID').agg({'InvoiceDate':'max','Sales':'sum','Invoice':'count'})
rfm['Recency'] = (last_date - rfm['InvoiceDate']).dt.days
rfm['Frequency'] = rfm['Invoice']
rfm['Monetary'] = rfm['Sales']
rfm_segment = rfm[['Recency','Frequency','Monetary']]
print(rfm_segment.head(5))
             Recency  Frequency  Monetary
Customer ID                              
12346.0          325          2      0.00
12347.0            1        182   4310.00
12348.0           74         31   1797.24
12349.0           18         73   1757.55
12350.0          309         17    334.40

Best Practices: Product Performance Analysis#

  • Analyzing product returns, margins, or sales trends guides assortment planning.
  • Poor performance might mean replacing or repricing a product.
  • Linking with catalog info gives a fuller insight (e.g., by price tier or category).
# Measure return rate by product
returns_by_prod = returns.groupby('Description')['Sales'].sum().sort_values()
total_by_prod = df.groupby('Description')['Sales'].sum()
return_rate = (returns_by_prod / total_by_prod).fillna(0).sort_values(ascending=False)
print('Products with highest return rates:')
print(return_rate.head(5))
Products with highest return rates:
Description
ROBIN CHRISTMAS CARD           252.000000
PINK SMALL GLASS CAKE STAND      9.000000
WOODEN BOX ADVENT CALENDAR       2.958425
Manual                           2.137483
PINK CHERRY LIGHTS               2.000000
Name: Sales, dtype: float64

Advanced: Market Basket Analysis#

  • Market basket analysis finds patterns in what products are bought together.
  • This analysis supports recommendations and product placement.
  • We simulate basket transactions to demonstrate association grouping.
# Create and analyze a simulated market basket transactions dataset
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))
market_basket = pd.DataFrame({'TransactionID': transaction_ids,'Product': product_choices})
pairs = (market_basket.groupby('TransactionID')['Product'].apply(lambda x: tuple(sorted(x))).value_counts())
print('Most common product triplets:')
print(pairs.head(3))
Most common product triplets:
Product
(Bread, Butter, Rice)        8
(Butter, Cheese, Chicken)    8
(Bread, Bread, Cheese)       6
Name: count, dtype: int64

Advanced: Demand and Trend Forecasting#

  • Demand forecasting predicts future sales using historical trends.
  • Retailers use it for stock management and campaign timing.
  • Simple moving averages help identify upward or downward trends.
# Calculate a 3-month moving average of sales
monthly_sales_ma = monthly_sales.rolling(3).mean()
print('3-month moving average of sales:')
print(monthly_sales_ma.tail(6))
3-month moving average of sales:
Month
2011-07    6.985856e+05
2011-08    6.850346e+05
2011-09    7.945561e+05
2011-10    9.243576e+05
2011-11    1.184050e+06
2011-12    9.887156e+05
Freq: M, Name: Sales, dtype: float64

End-to-End Retail Analytics: Actionable Insight#

  • Let us work through a mini-project: identify the top 3 products and recommend a stock increase.
  • We aggregate, rank, and explain the result for a business presentation.
  • This workflow combines all we learned into a real business recommendation.
# End-to-end example: Find and report top 3 products
final_top = product_sales.sort_values(ascending=False).head(3)
print('Recommendation: Increase stock for these products:')
for product, sales in final_top.items():
    print(f'{product}: $ {sales:,.2f}')
Recommendation: Increase stock for these products:
DOTCOM POSTAGE: $ 206,245.48
REGENCY CAKESTAND 3 TIER: $ 164,762.19
WHITE HANGING HEART T-LIGHT HOLDER: $ 99,668.47
 

Found this useful?

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