Data Analytics project 03
Customer Lifetime Value Analysis Project
Build a complete customer lifetime value analysis portfolio project with documented metrics, reproducible Python code, validation checks, and responsible interpretation.
Explore Data Analytics training in VizagView all project ideas
Business question
How much historical gross profit has each customer generated, and what is the monthly value since the first observed order?
Dataset and grain
Two thousand seeded synthetic completed orders across 400 anonymous customers, with order date, revenue, and gross-margin amount.
Requirements
Python 3.10 or later with numpy and pandas installed.
Method and validation checks
Apply an as-of date, aggregate first and last order, distinct order count, revenue, and gross profit, then divide observed profit by active months.
- Only orders before the as-of date are included
- Order count uses distinct IDs
- Gross profit is not confused with revenue
- The metric is labelled historical rather than predictive CLV
Complete Python code
Save the code as da_customer_lifetime_value.py. Review the stated model and field assumptions before using another dataset.
"""Estimate historical customer value from synthetic completed orders."""
from __future__ import annotations
import numpy as np
import pandas as pd
def make_demo_orders(n: int = 2_000, seed: int = 42) -> pd.DataFrame:
rng = np.random.default_rng(seed)
customer = rng.integers(1, 401, n)
revenue = rng.lognormal(6.5, 0.65, n)
gross_margin_rate = rng.uniform(0.28, 0.58, n)
return pd.DataFrame({"order_id": range(1, n + 1), "customer_id": customer,
"order_date": pd.Timestamp("2024-01-01") + pd.to_timedelta(rng.integers(0, 730, n), unit="D"),
"revenue": revenue.round(2), "gross_margin": (revenue * gross_margin_rate).round(2)})
def historical_clv(orders: pd.DataFrame, as_of: str = "2026-01-01") -> pd.DataFrame:
data = orders.copy()
data["order_date"] = pd.to_datetime(data["order_date"])
cutoff = pd.Timestamp(as_of)
data = data[data["order_date"] < cutoff]
result = data.groupby("customer_id", as_index=False).agg(
first_order=("order_date", "min"), last_order=("order_date", "max"),
orders=("order_id", "nunique"), revenue=("revenue", "sum"),
historical_gross_profit=("gross_margin", "sum"))
result["active_months"] = ((cutoff - result["first_order"]).dt.days / 30.4375).clip(lower=1)
result["monthly_gross_profit"] = result["historical_gross_profit"] / result["active_months"]
result["days_since_last_order"] = (cutoff - result["last_order"]).dt.days
return result.sort_values("historical_gross_profit", ascending=False).reset_index(drop=True)
def main() -> None:
clv = historical_clv(make_demo_orders())
print(clv.head(10).round(2).to_string(index=False))
print(f"Customers: {len(clv)} | Historical gross profit: {clv['historical_gross_profit'].sum():,.0f}")
print("This is observed historical value, not a prediction of future lifetime value.")
if __name__ == "__main__":
main()
Build and run the project
Run python da_customer_lifetime_value.py to generate customer-level historical gross-profit value.
- Confirm the source grain and field definitions.
- Reconcile record counts and additive totals.
- Validate rate denominators and date filters.
- Review outliers and missing values.
- Read the interpretation limits before sharing conclusions.
Expected analytical output
Customer recency, order count, revenue, historical gross profit, active months, and monthly gross-profit value.
Interpretation and responsible-use limits
This is observed value, not a forecast of future lifetime value. Real CLV needs acquisition cost, retention assumptions, discounting, margin definitions, refunds, censoring, and validation.
Ways to extend the project
Build cohort retention curves, probabilistic purchase models, acquisition-cost payback, discounted cash flow, and prediction backtests.
Continue learning Data Analytics
Try the next project, return to the Softenant project library, or explore the Data Analytics course in Vizag for guided SQL, Excel, Power BI, Python, dashboard, and portfolio practice.