EduFlow

Section 5 · Answering Real Questions

Case Study: Why Did Q4 2025 Revenue Jump?

26 min4 min readPython exercise

Lesson at a glance

Answer a real business question end to end - define the metric, check the data, decompose revenue into orders, customers and order value, test each explanation, and write a conclusion with its caveats.

  1. 1Step 1: define the metric and check the data
  2. 2Step 2: decompose the change
  3. 3Step 3: put it next to last year
  4. 4Step 4: test the popular explanations
  5. 5Step 5: write the answer

No video here — just the real thing: a written lesson, runnable examples, a quiz and practice.

The head of growth’s message has been waiting since Lesson 1.1: “Q4 2025 revenue was far higher than any quarter before. Was it Black Friday, more customers, bigger baskets, or a data mistake? I need an answer I can repeat to the board.” This lesson works through the answer the way you would at work: define, check, decompose, test explanations, conclude. Every step uses a tool you already know.

Step 1: define the metric and check the data

The metric is the course’s revenue definition from Lesson 4.2: line revenue after discounts, excluding shipping and cancelled orders. Build one row per order, and assert the facts the analysis relies on before trusting a single number:

Python
import pandas as pd

items = pd.read_csv("order_items.csv")
orders = pd.read_csv("orders.csv", parse_dates=["order_date"])
items["revenue"] = items["quantity"] * items["unit_price"] * (1 - items["discount"])
per_order = items.groupby("order_id", as_index=False)["revenue"].sum()
df = orders.merge(per_order, on="order_id", how="left", validate="one_to_one")

assert df["order_id"].is_unique
assert df["revenue"].notna().all(), "an order has no items"
df = df[df["status"] != "cancelled"].copy()
df["quarter"] = df["order_date"].dt.to_period("Q")

print(df.groupby("quarter")["revenue"].sum().round(0))
print(df.loc[df["quarter"] == "2025Q4", "status"].value_counts())

Revenue went from 80,523 dollars in Q3 2025 to 146,825 in Q4, up 82%. No duplicates, no orders without items. One caveat surfaces immediately: 63 Q4 orders worth 11,321 dollars, about 8% of the quarter, are still processing or shipped. They count as revenue under the definition, but some could still be cancelled. Note it now; it goes in the final answer.

Step 2: decompose the change

Revenue is orders times average order value, and orders are active customers times orders per customer. Computing each factor shows which one moved:

Python
import pandas as pd

items = pd.read_csv("order_items.csv")
orders = pd.read_csv("orders.csv", parse_dates=["order_date"])
items["revenue"] = items["quantity"] * items["unit_price"] * (1 - items["discount"])
df = orders.merge(items.groupby("order_id", as_index=False)["revenue"].sum(), on="order_id", validate="one_to_one")
df = df[df["status"] != "cancelled"].copy()
df["quarter"] = df["order_date"].dt.to_period("Q")

q = df.groupby("quarter").agg(
    revenue=("revenue", "sum"),
    orders=("order_id", "count"),
    customers=("customer_id", "nunique"),
)
q["aov"] = q["revenue"] / q["orders"]
q["orders_per_customer"] = q["orders"] / q["customers"]
print(q.round(2).tail(5))
print((q.loc["2025Q4"] / q.loc["2025Q3"] - 1).round(3))

The second print is the decomposition in one line. Orders rose 98% while average order value fell 8%: Q4 was about volume, not bigger baskets, which matches the medians you saw in Lesson 5.1. The extra orders came from both directions: 54% more active customers, and each ordered more often (2.28 orders per customer against 1.77).

Step 3: put it next to last year

A jump is only surprising compared with what normally happens. Lesson 4.4 already showed the comparison that matters:

Q3 → Q4 growth Year-over-year growth in Q4
2024 +73% (no 2023 data)
2025 +82% +180%

Q4 was 73% above Q3 in 2024 too, and November was the biggest month in both years. 2025’s Q3-to-Q4 rise is only somewhat stronger than the usual seasonal lift, and Q4’s 180% growth on the year before sits inside the range of the other 2025 quarters (145% to 200%). The board-level message starts to form: the business roughly tripled year over year (2025 revenue was 2.7 times 2024’s), and Q4 is that bigger business hitting its normal holiday peak.

Step 4: test the popular explanations

Each explanation gets one specific number:

Python
import pandas as pd

items = pd.read_csv("order_items.csv")
orders = pd.read_csv("orders.csv", parse_dates=["order_date"])
items["revenue"] = items["quantity"] * items["unit_price"] * (1 - items["discount"])
df = orders.merge(items.groupby("order_id", as_index=False)["revenue"].sum(), on="order_id", validate="one_to_one")
df = df[df["status"] != "cancelled"].copy()
df["quarter"] = df["order_date"].dt.to_period("Q")

first_q = df.groupby("customer_id")["order_date"].min().dt.to_period("Q").rename("first_quarter")
df = df.merge(first_q, on="customer_id", validate="many_to_one")
df["customer_type"] = (df["quarter"] == df["first_quarter"]).map({True: "new", False: "returning"})

q4 = df[df["quarter"] == "2025Q4"]
total = q4["revenue"].sum()
print(q4.groupby("customer_type")["revenue"].sum().div(total).round(3))
bf = q4["coupon_code"] == "BLACKFRIDAY25"
print("Black Friday coupon orders:", bf.sum(), "| share of Q4 revenue:", round(q4.loc[bf, "revenue"].sum() / total, 3))
print(q4.groupby(q4["order_date"].dt.month)["revenue"].sum().round(0))

Black Friday? The BLACKFRIDAY25 coupon was used on 69 Q4 orders, bringing 8.4% of the quarter’s revenue. November was huge, 75,334 dollars, but most of it came from orders without that coupon. Black Friday helped; it does not explain the jump. New customers? Customers placing their first order brought 36% of Q4 revenue, while 64% came from returning customers, who also account for two thirds of the 66,302-dollar rise over Q3. The jump rests mostly on an existing customer base that kept growing and kept coming back. Bigger baskets? Ruled out in Step 2. Price rise? The 5% increase took effect in March 2025, so it lifts Q3 and Q4 equally and explains none of the change between them. Data mistake? The checks in Step 1 found no duplicates or orphaned orders; the only open risk is the 8% not yet delivered.

Five steps in a row: define and check, decompose, compare with last year, test explanations, conclude. Under each step, its finding: data clean with 8 percent undelivered; orders up 98 percent and order value down 8 percent; 2024 had a 73 percent Q4 lift too; Black Friday coupons 8 percent and returning customers 64 percent; seasonal peak on a business that tripled. Check Decompose Last year Test ideas Conclude clean;8% undelivered orders +98%AOV -8% 2024 Q4 liftwas +73% coupon 8%;returning 64% seasonal peakon a 2.7x business
From question to answer: each step narrows the explanation

Step 5: write the answer

The analysis is only finished when someone else can repeat it in a meeting. Lead with the conclusion, give the evidence in numbers, end with the caveats:

Q4 2025 revenue (146,825 dollars, +82% on Q3) was mainly Cartwheel’s normal holiday peak on a business that grew 2.7x year over year. The rise came from order volume (+98%), not order size (average order value fell 8%), with 54% more active customers ordering more often. Q4 was 73% above Q3 in 2024 as well. Returning customers produced 64% of Q4 revenue; Black Friday coupon orders produced 8.4%. Caveats: 8% of Q4 revenue is from orders not yet delivered, and the decline in order value is partly the cost of Q4 discounts, which more than tripled on Q3 (5,581 dollars versus 1,615).

In the exercise you rebuild the decomposition in code. The final lesson turns this analysis into something you can rerun next quarter without starting over.

Key takeaways

  • Start a business question by writing down the metric and its exact definition, then check the data that feeds it before any analysis.
  • Decompose a total into drivers (revenue = orders × average order value; orders = customers × orders per customer) to see which one moved.
  • Compare against the same period last year and against the seasonal pattern, so a normal peak is not mistaken for a breakthrough.
  • Test each popular explanation with a specific number, and say how much of the change it can and cannot explain.
  • A finished answer is a short conclusion, the evidence behind it, and the caveats that could change it.

Further reading

Check your understanding

3 questions

Question 1 of 3

Q4 revenue rose 82% on Q3 while orders rose 98% and average order value fell 8%. What drove the increase?

Question 2 of 3

Q4 2024 was also 73% above Q3 2024. Why does that matter for the Q4 2025 story?

Question 3 of 3

63 Q4 orders worth 11,321 dollars are still processing or shipped at the end of the data. How should the report treat them?

Practice

Python exercise

Decompose the Q4 jump

df has one row per non-cancelled order with revenue, customer_id, coupon_code and a quarter period. Build q, one row per quarter with revenue (sum), orders (count), customers (distinct customers) and aov (revenue ÷ orders). Then compute the Q3-to-Q4 2025 growth of revenue, orders and AOV as fractions (revenue_growth, orders_growth, aov_growth), the share of Q4 2025 revenue from BLACKFRIDAY25 orders (bf_share), and the 2024 Q3-to-Q4 revenue growth (growth_2024). Round each of these five numbers to 3 decimals.

Data files: order_items.csv, orders.csv

import pandas as pd

items = pd.read_csv("order_items.csv")
orders = pd.read_csv("orders.csv", parse_dates=["order_date"])
items["revenue"] = items["quantity"] * items["unit_price"] * (1 - items["discount"])
df = orders.merge(items.groupby("order_id", as_index=False)["revenue"].sum(), on="order_id", validate="one_to_one")
df = df[df["status"] != "cancelled"].copy()
df["quarter"] = df["order_date"].dt.to_period("Q")

# 1. q: one row per quarter with columns revenue, orders, customers (distinct), aov
q = None

# 2. Growth from 2025Q3 to 2025Q4 as fractions (0.5 = +50%), each rounded to 3 decimals
revenue_growth = None
orders_growth = None
aov_growth = None

# 3. Share of 2025Q4 revenue from orders with the BLACKFRIDAY25 coupon, rounded to 3 decimals
bf_share = None

# 4. Q3-to-Q4 revenue growth in 2024, rounded to 3 decimals (the seasonal baseline)
growth_2024 = None
Loading the editor…

Ctrl/⌘ + Enter to run · Runs in a sandbox in your browser. Nothing leaves your device.

(no output)

Checks

  • q has 8 quarters with revenue, orders, customers and aov
  • Q4 2025 shows 642 orders, 282 customers and an AOV of 228.70
  • Revenue grew 82.3% and orders 98.1%
  • AOV fell 8.0%
  • Black Friday coupon orders are 8.4% of Q4 revenue
  • 2024’s Q3-to-Q4 growth was 72.7%