Chapter 25 — Business Analytics and KPI Dashboards

Business analytics turns operational data into decisions. This chapter builds a synthetic orders dataset, computes core KPIs, performs cohort analysis, and assembles the elements of a KPI dashboard.

Learning Objectives

Prerequisites / Imports

In [1]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style='whitegrid')

1 Build an Orders Fact Table

We synthesize a year of orders across regions and products.

In [1]:
rng = np.random.default_rng(7)
n_days = 365
orders = pd.DataFrame({
    'date': pd.date_range('2026-01-01', periods=n_days, freq='D'),
    'region': rng.choice(['North','South','East','West'], n_days),
    'product': rng.choice(['Widget','Gadget','Cable'], n_days, p=[0.5,0.3,0.2]),
    'units': rng.integers(1, 20, n_days),
    'unit_price': rng.choice([4.5, 12.75, 1.2], n_days),
})
orders['revenue'] = orders['units'] * orders['unit_price']
orders.head()
date region product units unit_price revenue
0 2026-01-01 West Gadget 17 1.20 20.40
1 2026-01-02 East Cable 2 4.50 9.00
2 2026-01-03 East Widget 10 12.75 127.50
3 2026-01-04 West Widget 2 12.75 25.50
4 2026-01-05 East Widget 3 12.75 38.25

2 Core KPIs

Total revenue, average order value (AOV), daily orders, and total units.

In [1]:
kpis = {
    'Total revenue ($)': round(float(orders['revenue'].sum()), 2),
    'Average order value ($)': round(float(orders['revenue'].mean()), 2),
    'Total units sold': int(orders['units'].sum()),
    'Orders per day': round(float(len(orders)/n_days), 2),
}
for k, v in kpis.items():
    print(f'{k}: {v}')
Total revenue ($): 23392.2
Average order value ($): 64.09
Total units sold: 3604
Orders per day: 1.0

3 Revenue by Segment

Group by product and region to find the best performers.

In [1]:
orders.groupby('product')['revenue'].agg(['sum','mean']).round(2)
sum mean
product
Cable 4243.50 63.34
Gadget 7136.55 58.98
Widget 12012.15 67.87
In [1]:
pivot = orders.pivot_table(index='region', columns='product', values='revenue', aggfunc='sum').round(0)
pivot
product Cable Gadget Widget
region
East 1136.0 1999.0 3152.0
North 1096.0 1564.0 4041.0
South 758.0 1309.0 2471.0
West 1254.0 2265.0 2348.0

4 Revenue Over Time

Monthly revenue trend reveals seasonality and growth.

In [1]:
monthly = orders.set_index('date')['revenue'].resample('MS').sum()
plt.figure(figsize=(10,4))
monthly.plot()
plt.title('Monthly revenue'); plt.ylabel('revenue ($)')
plt.show()

5 Cohort Analysis

A cohort groups customers by their first-purchase month; retention is the share still active in later months. We approximate cohorts by joining month.

In [1]:
orders['month'] = orders['date'].dt.to_period('M')
orders['cohort'] = orders['date'].dt.to_period('M').astype(str)
cohort_sizes = orders.groupby('cohort').size()
print(cohort_sizes.head())
cohort
2026-01    31
2026-02    28
2026-03    31
2026-04    30
2026-05    31
dtype: int64

6 Retention Curve

We simulate repeat purchases over 12 monthly cohorts to illustrate a retention curve.

In [1]:
rng = np.random.default_rng(11)
months = pd.period_range('2026-01', periods=12, freq='M')
retention = []
for i, m in enumerate(months):
    # retention decays from 100% over following months
    decay = np.exp(-0.25*np.arange(12-i))
    retention.append(np.round(decay*100, 1))
ret_df = pd.DataFrame(retention, index=[str(m) for m in months]).T
ret_df.iloc[:6, :6]
2026-01 2026-02 2026-03 2026-04 2026-05 2026-06
0 100.0 100.0 100.0 100.0 100.0 100.0
1 77.9 77.9 77.9 77.9 77.9 77.9
2 60.7 60.7 60.7 60.7 60.7 60.7
3 47.2 47.2 47.2 47.2 47.2 47.2
4 36.8 36.8 36.8 36.8 36.8 36.8
5 28.7 28.7 28.7 28.7 28.7 28.7

Case Study: A KPI Dashboard

Combine the key visuals into a single multi-panel dashboard — the form a business stakeholder actually wants.

In [1]:
fig, axes = plt.subplots(2, 2, figsize=(13, 9))
# Top-left: monthly revenue
monthly.plot(ax=axes[0,0], color='steelblue'); axes[0,0].set_title('Monthly revenue')
# Top-right: revenue by product
rev_prod = orders.groupby('product')['revenue'].sum()
axes[0,1].bar(rev_prod.index, rev_prod.values, color='teal'); axes[0,1].set_title('Revenue by product')
# Bottom-left: units distribution
axes[1,0].hist(orders['units'], bins=20, color='coral', edgecolor='black'); axes[1,0].set_title('Units per order')
# Bottom-right: AOV by region
aov = orders.groupby('region')['revenue'].mean()
axes[1,1].bar(aov.index, aov.values, color='slateblue'); axes[1,1].set_title('AOV by region')
plt.tight_layout()
plt.show()

Exercises

  1. Compute total revenue and AOV for a synthetic orders dataset.
  2. Pivot revenue by region and product.
  3. Plot monthly revenue over a year.
  4. Define AOV and explain how it differs from total revenue.
  5. Build a 2x2 dashboard of four business charts.
  6. Compute each product's share of total revenue.
  7. Simulate 12 cohorts and plot a retention curve.
  8. Identify the top region by revenue and by AOV.
  9. Explain why cohort analysis matters for subscription businesses.
  10. Write a one-paragraph summary of findings for a manager.

Python Data Science: From Foundations to Applications — Chapter 25