Every data team believes it is further up the analytics ladder than it actually is.
Ask a C-Levels where their organization stands and you will hear words like “predictive”, “AI-powered”, and “we’re doing machine learning now”. Then sit in one of their planning meetings and watch what actually happens. Two analysts spend the first twenty minutes arguing about which dashboard has the correct revenue number. The machine learning initiative is blocked because nobody trusts the labels in the CRM. The AI strategy is a slide deck.
This gap between self-perception and reality is so consistent that Gartner quantified it years ago. At its 2017 Data & Analytics Summit, Gartner reported that 74% of organizations had descriptive analytics capabilities in place, 34% had diagnostic, 11% had predictive, and only 1% had prescriptive. The pyramid narrows brutally fast, and almost everyone overestimates which floor they are standing on.
Gartner’s framework for this is called the Analytic Ascendancy Model, and it remains one of the most honest tools a data leader can use. It separates organizations into four stages based on what their data can actually do, not what their tooling vendor promised. Most companies are stuck at the bottom. The ones that climb unlock disproportionate value, but only if they build each layer properly. Here is how the ladder works, where you actually stand, and what to fix before you take the next step.
The analytics maturity model is a framework that classifies an organization’s data capabilities into stages based on the questions its data can answer:
what happened, why it happened, what will happen, and what should be done about it.
Gartner introduced the idea as the Analytic Ascendancy Model, and it borrows its philosophy from the Capability Maturity Model that software engineering developed decades earlier. The core premise is the same in both worlds: capabilities develop in stages, each stage is the foundation for the next one, and you cannot buy your way to the top by purchasing tools.
Two things increase together as you climb. The first is business value. Knowing what happened last quarter is useful. Knowing what will happen next quarter is worth more. Knowing exactly which action to take, with what budget, under which constraints, is worth more still. The second is difficulty, and this is the part nobody puts in the vendor pitch. Each stage demands more technical sophistication, better data infrastructure, and harder organizational habits than the one below it.
There is also a clean dividing line through the middle of the model. The first two stages look backward. They are hindsight. The last two look forward. They are foresight. Crossing that line is where most organizations stall, because foresight requires a fundamentally different relationship with data than reporting does.
Each stage is defined by one question. Descriptive asks what happened. Diagnostic asks why. Predictive asks what will happen. Prescriptive asks how we can make it happen. Here is the full picture, including who typically does the work at each level.
Notice that the jump from stage 2 to stage 3 is the only one that crosses the hindsight to foresight line. That is why it feels like a different sport rather than an incremental upgrade, and why so many teams never make it.
This is the foundation, and almost everyone lives here at first. Dashboards, SQL queries, weekly/monthly KPI reports, and OLAP cubes all fall into this stage. Descriptive analytics summarizes historical data so the organization knows what happened: revenue last month, signups by channel, tickets closed per agent.
When done well, this stage is more than report generation. It means governed data with consistent definitions, so that “monthly revenue” means the same thing in finance, in marketing, and in the executive deck. It means reports are credible enough that nobody re-runs the numbers before a decision. That trust is the real product of stage 1, not the charts.
You can tell your team is stuck here when every meeting starts with a debate about which numbers are correct, when every request is “pull this number for me”, and when reports arrive after the decision they were meant to inform has already been made. At that point the analytics function is reactive by design, explaining last month instead of shaping next month.
Here is the uncomfortable part for teams comfortable at this level. Large language models and text-to-SQL tools are commoditizing basic reporting fast. A manager can now ask a chatbot “what were signups by region last week” and get a chart in seconds. The defensible value of stage 1 is no longer the reports themselves. It is the clean, governed data infrastructure underneath them, which every higher stage depends on.
Diagnostic analytics digs into root causes. When a descriptive dashboard shows that revenue dropped 20% in April, diagnostic work answers why. The toolkit includes drill-downs, correlation analysis, cohort comparisons, segmentation, and hypothesis testing. This is where basic statistics meets business context.
The skill that defines this stage is asking better questions of clean data. A diagnostic analyst does not just see that churn spiked. They isolate that it spiked in one customer segment, starting the week a pricing change shipped, and they can defend that finding with a statistical test rather than a hunch.
Correlation matrices like the one above are a diagnostic staple, and they illustrate both the power and the danger of this stage. A strong correlation between ad spend and conversions is a hypothesis worth investigating. It is not proof that ad spend caused the conversions. Teams that blur that line carry bad habits into every later stage.
Here is the difference between descriptive and diagnostic work on the same problem. The descriptive version compares overall averages and shrugs. The diagnostic version segments the data, finds where the change actually lives, and verifies it with a test. Here is an example code that you can run for this demonstration:
"""diagnostic_root_cause_analysis.pyStage 2 (diagnostic analytics) example: find out WHY a KPI moved.Simulates a SaaS revenue dataset where a pricing change quietly hurtonly the Enterprise segment, then contrasts two approaches:Bad pattern: compare overall monthly averages (descriptive only).Good pattern: drill down by segment, then verify with Welch's t-test."""import numpy as npimport pandas as pdfrom scipy import statsrng = np.random.default_rng(42)days = 31# Simulated daily revenue. In April, a pricing change quietly hurt# only the Enterprise segment.df = pd.concat([ pd.DataFrame({ "month": "March", "segment": ["SMB"] * days + ["Enterprise"] * days, "daily_revenue": np.concatenate([ rng.normal(52_000, 3_000, days), # SMB: stable rng.normal(78_000, 4_000, days), # Enterprise: healthy baseline ]), }), pd.DataFrame({ "month": "April", "segment": ["SMB"] * days + ["Enterprise"] * days, "daily_revenue": np.concatenate([ rng.normal(52_500, 3_000, days), # SMB: still stable rng.normal(66_000, 4_500, days), # Enterprise: sharp drop ]), }),])# --- Bad: descriptive only. Overall averages blend the segments together# --- and hide where the drop actually came from.overall = df.groupby("month")["daily_revenue"].mean()print("Descriptive view (overall average daily revenue):")print(overall.round(0).to_string())print(f"Overall change: {(overall['April'] / overall['March'] - 1):+.1%}\n")# --- Good: diagnostic. Drill down by segment first.by_segment = ( df.groupby(["segment", "month"])["daily_revenue"] .mean() .unstack())by_segment["change_pct"] = by_segment["April"] / by_segment["March"] - 1print("Diagnostic view (average daily revenue by segment):")print(by_segment[["March", "April"]].round(0).to_string())for segment, row in by_segment.iterrows(): print(f" {segment}: {row['change_pct']:+.1%}")# --- Verify with Welch's t-test: is each segment's drop statistically real?print()for segment in ["SMB", "Enterprise"]: before = df[(df.segment == segment) & (df.month == "March")].daily_revenue after = df[(df.segment == segment) & (df.month == "April")].daily_revenue t, p = stats.ttest_ind(before, after, equal_var=False) print(f"{segment}: change = {after.mean() - before.mean():+,.0f}, p = {p:.4f}")
The overall average shows a modest decline that invites vague explanations. The segmented view pins the entire drop on Enterprise customers, with a p-value that rules out noise. That is the difference between knowing what happened and knowing why.
The limitation of this stage is the same as the last one: it looks backward. Understanding the past is not the same as anticipating the future. For that, you need the next rung.
Predictive analytics uses statistical models and machine learning to forecast what will happen before it happens. Churn prediction, demand forecasting, fraud scoring, and lead scoring all live here. This is the stage where data science teams earn their budget, and where the word “AI” in your strategy deck finally refers to something real.
The requirements are what make this stage hard. You need labeled historical outcomes, because supervised models learn from examples of what already happened. You need features that actually carry signal, which is where the diagnostic stage pays off: you cannot engineer good features for churn if you never investigated why customers leave. And you need validation discipline, because a model that looks great on its training data and fails in production is worse than no model at all. It makes decisions with unearned confidence.
Here is a complete, runnable churn prediction pipeline code example: simple cross-validated scoring before final training, a proper holdout set, and probability outputs rather than hard labels.
"""churn_prediction.pyStage 3 (predictive analytics) example: train a gradient boosting modelthat predicts customer churn before it happens.Self-contained version of the pipeline: it synthesizes a realisticcustomer feature table (2,000 customers, ~20% churn), then trains andevaluates the model with cross-validation and a holdout test set."""import numpy as npimport pandas as pdfrom sklearn.model_selection import train_test_split, cross_val_scorefrom sklearn.ensemble import GradientBoostingClassifierfrom sklearn.preprocessing import StandardScalerfrom sklearn.pipeline import Pipelinefrom sklearn.metrics import classification_report, roc_auc_score# Synthetic customer base: 2,000 customers, roughly 20% churn.# Churned customers show weaker engagement signals on every feature.rng = np.random.default_rng(42)n = 2000churned = rng.random(n) < 0.2df = pd.DataFrame({ "tenure_months": np.where(churned, rng.integers(1, 18, n), rng.integers(6, 48, n)), "monthly_spend": np.where(churned, rng.normal(45, 15, n), rng.normal(70, 20, n)), "support_tickets": np.where(churned, rng.poisson(3.5, n), rng.poisson(1.0, n)), "login_frequency": np.where(churned, rng.normal(1.5, 1, n), rng.normal(5, 2, n)), "days_since_last_login": np.where(churned, rng.integers(10, 45, n), rng.integers(0, 14, n)), "plan_tier": rng.choice(["basic", "pro", "enterprise"], n, p=[0.5, 0.35, 0.15]), "churned": churned.astype(int),})FEATURES = [ "tenure_months", "monthly_spend", "support_tickets", "login_frequency", "days_since_last_login", "plan_tier",]TARGET = "churned"X = pd.get_dummies(df[FEATURES], columns=["plan_tier"])y = df[TARGET]X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, stratify=y, random_state=42)# Pipeline: scale features then train GBMpipeline = Pipeline([ ("scaler", StandardScaler()), ("clf", GradientBoostingClassifier( n_estimators=200, max_depth=4, learning_rate=0.05, random_state=42, )),])# Cross-validated AUC before final training, so you never tune on the test setcv_auc = cross_val_score(pipeline, X_train, y_train, cv=5, scoring="roc_auc")print(f"CV ROC-AUC: {cv_auc.mean():.4f} +/- {cv_auc.std():.4f}")# Fit and evaluate on holdout test setpipeline.fit(X_train, y_train)y_prob = pipeline.predict_proba(X_test)[:, 1]auc = roc_auc_score(y_test, y_prob)print(f"\nTest ROC-AUC: {auc:.4f}")print(classification_report(y_test, pipeline.predict(X_test)))
A model like this turns a vague fear (“customers seem unhappy”) into a scored list of at-risk accounts, ranked by probability. That is genuine foresight, and it is worth real money in business.
But notice what the model does not do. It does not tell you which retention offer to send, how much to spend, or which customers are worth saving at all. A prediction without a recommended action still leaves a human staring at a spreadsheet, deciding what to do with their gut. Prediction creates foresight. Action requires the next stage.
Prescriptive analytics is the summit. It does not just predict outcomes. It recommends specific actions to achieve the best one, given your constraints. Mathematical optimization, simulation, reinforcement learning, and recommendation engines all fall here.
Where a predictive system hands you a list of customers likely to churn, a prescriptive system hands you a plan: which customers to target, with which intervention, through which channel, under a fixed budget, to maximize retained revenue. This is the stage where analytics stops informing decisions and starts making them, either as recommendations a human approves or as fully automated decision loops.
The feedback loop in that diagram is the part most teams miss. A prescriptive system that never measures whether its recommendations worked is just an opinion generator with extra steps. The loop is what turns it into a learning system.
Here is what the optimization core looks like in practice. Given the churn model’s at-risk list from the previous section, allocate a limited retention budget across four interventions to maximize expected saved revenue.
"""prescriptive_budget_optimization.pyStage 4 (prescriptive analytics) example: given the churn model'sat-risk list, allocate a limited retention budget across interventionsto maximize expected saved revenue, using linear programming.Contrasts the optimizer's allocation with a naive equal split of thebudget, which is what most teams do out of habit."""from scipy.optimize import linprog# Each intervention has a cost per customer and a historically measured# probability of saving the customer (from past experiments).interventions = { "discount_offer": {"cost": 25, "save_rate": 0.30}, "success_checkin": {"cost": 15, "save_rate": 0.15}, "loyalty_perk": {"cost": 40, "save_rate": 0.38}, "onboarding_call": {"cost": 60, "save_rate": 0.45},}LTV = 400 # expected revenue saved per retained customerBUDGET = 20_000 # retention budget this quarterAT_RISK = 900 # customers flagged by the Stage 3 churn modelMAX_REACH = 400 # operational capacity per interventionnames = list(interventions)# Decision variables: x_i = number of customers receiving intervention i.# Maximize expected saved revenue = sum(save_rate_i * LTV * x_i).# linprog minimizes, so negate the per-customer value.c = [-interventions[n]["save_rate"] * LTV for n in names]# Constraints:# 1. Total spend cannot exceed the budget.A_ub, b_ub = [[interventions[n]["cost"] for n in names]], [BUDGET]# 2. Each intervention has an operational reach limit.for i in range(len(names)): row = [0] * len(names) row[i] = 1 A_ub.append(row) b_ub.append(MAX_REACH)# 3. Cannot target more customers than the churn model flagged.A_ub.append([1] * len(names))b_ub.append(AT_RISK)res = linprog(c, A_ub=A_ub, b_ub=b_ub, bounds=[(0, None)] * len(names), method="highs")print("Optimal allocation of at-risk customers:")for n, x in zip(names, res.x): print(f" {n:16s} {x:6.0f} customers (${x * interventions[n]['cost']:,.0f})")print(f"\nExpected customers saved: {-res.fun / LTV:,.0f}")print(f"Expected revenue saved: ${-res.fun:,.0f}")# --- Naive baseline for contrast: split the budget evenly across the# --- four interventions instead of optimizing.print("\nNaive equal-split baseline:")naive_saved_revenue = 0.0for n in names: spend = BUDGET / len(names) reached = min(spend / interventions[n]["cost"], MAX_REACH) naive_saved_revenue += reached * interventions[n]["save_rate"] * LTV print(f" {n:16s} {reached:6.0f} customers (${spend:,.0f})")print(f"\nExpected revenue saved: ${naive_saved_revenue:,.0f}")print(f"Optimizer advantage: ${-res.fun - naive_saved_revenue:,.0f}")
The optimizer fills the cheapest, highest-value interventions first and spends what is left on the next best option, rather than splitting the budget evenly out of habit. With these numbers it beats a naive equal split by thousands of dollars per quarter, and the gap widens as constraints get messier.
Prescriptive systems carry a responsibility the other stages do not. Because they drive action, a mistake is not a wrong chart on a wall. It is money spent, customers annoyed, or inventory misallocated. That is why this stage demands the strongest governance, the best monitoring, and a human in the loop until the system has earned trust.
Here is the part of the model that separates people who have read about it from people who have used it. The four stages are not a menu. You do not get to pick the one that sounds impressive. They form a dependency chain, and every stage consumes the output of the stage below it. I mean if you have read everything up until this point it is kind of obvious now.
Prescriptive analytics requires accurate predictions, because an optimizer choosing actions from bad forecasts will confidently recommend the wrong actions. Predictive analytics requires correct root-cause understanding and trustworthy historical labels, because models learn whatever your past data says, including its errors. Diagnostic analytics requires accurate, consistent reporting, because you cannot investigate a KPI that nobody can define. And descriptive analytics requires clean, governed data infrastructure: pipelines that run on time, definitions that are documented, and access that is controlled. That infrastructure is rung zero, and it is where most climbing actually begins.
Skip a step and everything above it collapses. A churn model trained on dirty reporting data produces bad forecasts. Bad forecasts fed into an optimizer produce harmful recommendations. And because each stage amplifies what it receives, errors do not just persist as you climb. They compound.
Knowing the ladder is not enough. Most organizations that fail do so in one of five predictable ways.
The most common mistake, by far. Teams want to build ML models before their reporting layer is trustworthy, because models make better slide decks than data governance does. The executive sponsor asks for AI, nobody asks whether the underlying data can support it, and eighteen months later the project is a cautionary tale. Climb in order, even when it is boring.
Diagnostic tools like correlation matrices generate hypotheses, not proof. Teams get into trouble when they use a predictive model’s feature importance to make causal claims, then design interventions around them. If support tickets correlate with churn, cutting support access to reduce tickets will not reduce churn. It will accelerate it. Causal claims need experiments, ideally A/B tests, not just strong correlations.
Prescriptive systems do exactly what you tell them to, which is terrifying when you told them the wrong thing. Maximize clicks and the optimizer learns clickbait. Maximize short-term conversions and it quietly torches long-term retention. Before you build a prescriptive system, spend real time on the objective function, and remember Goodhart’s law: the moment a proxy metric becomes the target, it stops being a good measure of the real goal.
Some organizations perform maturity instead of building it. They buy the analytics platform, hire the job titles, and rate themselves a stage 4 on a self-assessment because the tooling exists. The honest test is behavioral, not architectural: when a KPI moves unexpectedly, what does your team actually do in the next 48 hours? The answer to that question is the real maturity level of your data team.
Models drift as customer behavior changes. Optimization constraints go stale as the business evolves. Data pipelines break quietly. Maturity is maintained, not achieved, and organizations that stop investing in the lower rungs eventually discover the upper ones no longer work.
Self-assessments inflate, so assess with evidence instead of opinions. The trick is to audit what your organization does under pressure, not what it claims in strategy documents.
Notice that every piece of evidence is observable behavior. Not a tool you bought. Not a role you hired. What happens, in practice, when the data has something to say.
Score each dimension separately rather than giving the whole company one number. Your marketing team may genuinely be predictive while finance is still descriptive, and a single company-wide score hides exactly the information you need to plan.
Then pick exactly one rung to climb next. The model’s value is not in telling you where you are. It is in making the next move obvious. If your diagnostic work is shaky, do not fund a machine learning initiative. Fund better segmentation, experimentation habits, and statistical literacy. If your predictions are solid but nobody acts on them, the bottleneck is not modeling. It is the bridge between insight and decision, which is where prescriptive work lives.
Most organizations operate somewhere between descriptive and diagnostic, no matter what their strategy deck says. Reaching predictive and prescriptive analytics is a multi-year investment in data quality, tooling, and talent, and the organizations that get there did not do it by being smarter. They did it by being honest about where they started and refusing to skip rungs.
The analytics maturity model is not a ranking to brag about. It is a mirror, and then a map. Be honest about where you stand, fix the layer beneath you, and only then take the next step. Build the foundation before you chase the frontier.
Here are several key takeaways from this article:
Thank you for reading this article! I hope you found it helpful. If you have any questions or feedback, please feel free to reach out to me.
#DataScience #Analytics #MachineLearning #BusinessIntelligence #DataAnalytics #ArtificialIntelligence #Leadership #DataDriven
The Analytics Maturity Model: How to Know Where Your Data Team Actually Stands was originally published in Towards AI on Medium, where people are continuing the conversation by highlighting and responding to this story.