cswork / libraryOpen practice workspace

Interview guides · CATERPILLAR

CATERPILLAR Data Scientist Interview Questions & Guide 2026

Data scientist prep for CATERPILLAR candidates: drill A/B design, power and minimum detectable effect on original exercises.

The 60-second brief

As a Data Scientist at CATERPILLAR, you sit at the intersection of heavy industrial engineering, IoT telemetry, and advanced predictive analytics. Your work directly influences how massive fleets of machinery operate, how supply chains optimize component delivery, and how predictive maintenance models prevent costly downtime for global customers. You will build and deploy models that process vast streams of operational data from connected heavy equipment, translating raw telemetry and operational metrics into actionable business value.

Ask early whether the loop includes an asynchronous take-home or a timed live case, because the two are graded on different things. A take-home is read as an artifact: the question you decided to answer, what you did about missing or malformed records, and a conclusion stated plainly enough for someone to act on. A reviewer who cannot rerun your notebook discounts the result whatever score is printed in it. Hold to the stated time box and write down what you would have done with more of it, since the follow-up round is usually a live defence of the same work.

Focus areas

  • Trace an on-time miss to one node
  • Separate true demand from censored, stocked-out sales
  • Size safety stock under variable lead times

Overview

This role requires a unique balance of rigorous statistical methodology and robust product-sense. You will collaborate closely with product managers, data engineers, and domain experts to design metric frameworks, evaluate new feature rollouts via experimentation, and diagnose unexpected shifts in key operational metrics. Whether you are optimizing connected asset performance or forecasting dealer inventory requirements, your insights drive mission-critical decisions across the enterprise.

Expect a collaborative, engineering-driven culture that values accountability, technical depth, and clear communication. While the problems you tackle involve complex industrial scale, interviewers place a heavy emphasis on your ability to explain technical trade-offs to non-technical stakeholders. Success in this role demands strong foundational coding, sound statistical reasoning, and the ability to connect data models back to real-world operational impact.

The CATERPILLAR interview process

CATERPILLAR candidates report 4 rounds · ≈ 3-5 weeks. The stages below are what candidates describe, not a published process.

Recruiter Screen

Data Scientist covers at least four different jobs: experimentation, product analytics, causal work on observational data, and applied modelling that ships into a system. A screening call is the cheapest place to find out which of them is being hired for, and doing that diagnosis openly reads as senior rather than fussy. Ask what the last few pieces of work on the team actually were, and roughly how a week splits between querying, modelling and stakeholder time. Then say which parts of that you have done and which you have not. Claiming the whole range is the fastest way to be caught one round later.

What to demonstrate

  • Whether you can distinguish the flavours of the role and locate your own experience inside one of them honestly
  • Whether you name what you have not done instead of stretching to cover every line of the posting
  • Whether your hard constraints (notice period, location, work authorisation, level) surface now rather than at offer stage

How to prepare

  • Map the last two years of your time into rough percentages across query writing, experiment design, modelling and stakeholder work, so a question about scope has a real answer
  • Mark every responsibility in the posting as done, adjacent or new, and prepare one sentence for each adjacent item naming the closest thing you have actually built
  • Decide which logistics are non-negotiable before the call so you can state them in one sentence rather than negotiating live

Technical Rounds

This round decides whether someone can hand you a schema and a question and trust the number that comes back. Correctness under a clock is the bar, not clever syntax. The habit that separates strong from weak answers is checking the grain: after every join, know how many rows you expect and whether the count moved. Most wrong answers in this format are not wrong logic, they are a fan-out from a key that turned out not to be unique, or a filter applied before an aggregate when it belonged after. Say what you expect before you run it.

What to demonstrate

  • Whether your row counts survive each join, and whether you notice on your own when they do not
  • Deliberate handling of rows that fail to match, including whether the question needs an inner join or a left join with the non-matches kept and counted
  • Whether NULLs are treated on purpose, given that a NULL compares equal to nothing and that COUNT of a column skips it
  • Reaching a defensible answer inside the window instead of a refined one after it

How to prepare

  • Take a two-table schema, write a join that fans out on purpose, then fix it by collapsing the many-side to one row per key before joining. Repeat until the fix is reflex rather than recall.
  • Write a funnel as one query and print the distinct user count at each stage, then confirm each stage is a subset of the one above it rather than assuming it
  • Do a few timed runs in a plain text box with no autocomplete and no formatter, since assessment editors often have neither

Panel Interview

Where a loop includes a partner from outside the data team, that conversation usually carries the same weight as the technical ones and gets the least preparation. The person opposite you will not follow a derivation and does not need to. They are working out whether having you involved would make their decisions better or slower. The failure mode is not being too technical. It is answering a question about a decision with a description of your method, leaving the translation to them. What they carry into the debrief is the sentence you handed them, not the analysis underneath it.

What to demonstrate

  • Whether a statistical result arrives as something the partner could act on, with the one caveat that would change their decision kept and the rest left out
  • Whether you can state what you need from their side, in their terms: instrumentation that does not exist yet, a definition they own, or a holdout they have to agree to
  • Whether uncertainty is given as a range someone can plan against, rather than as hedging that invites them to ignore the result
  • Whether you ask what decision is actually on the table before explaining anything

How to prepare

  • Take a result you know well and write the version for someone who stops reading after one sentence, then the three-minute version, and check the short one is not the long one with the qualifications stripped out
  • For a past project, list everything you asked a non-technical partner for and how you phrased it, then rewrite each ask so it names what goes unmeasured without it
  • Practise saying where a result does not apply, out loud, in one sentence that a partner could repeat accurately to someone else

Group Exercise

An extra round usually exists because something is still open after the standard loop: a skill the earlier interviews did not sample, a level decision, or two interviewers who disagreed. It is rarely a rerun of what you already did well. Ask the recruiter who you are meeting, what function they sit in, and how long the session runs. That is an ordinary scheduling question, and the answer changes what you should prepare. What separates a strong candidate here is treating the round as a fresh evaluation with its own bar, rather than assuming earlier performance carries you through or sinks you.

What to demonstrate

  • Whether you can answer well on ground the earlier rounds did not cover, without leaning on what you already said to someone else
  • Consistency of the facts in your stories: the same sample size, timeframe, team size and scope of your own role as in earlier conversations
  • How you handle an unfamiliar format live, including whether you ask what kind of answer is wanted before producing one

How to prepare

  • Ask the recruiter for the interviewer's function, the length, and whether to expect a coding surface, a discussion, or a presentation. Preparing for a 30 minute conversation with a partner team is not the same work as preparing for a 60 minute technical block.
  • Write out what each earlier round actually covered, then list the two or three areas nobody probed. That gap is the most likely subject of the extra round.
  • Re-read the numbers in the project stories you have already told, so a second telling does not quietly contradict the first.

Where candidates lose points

Computing average inventory from period-end snapshots

Shipments cluster before period close, so the month-end on-hand position is systematically the lowest point of the month; turns computed against it are biased high and days of supply biased low, frequently by ten to twenty percent, and the bias grows precisely when close-period push is strongest. The same shape of error appears when a daily snapshot is joined to shipment events on date equality: a SKU with several legs on one day fans the snapshot out and multiplies the valued inventory. Average across every daily snapshot in the window for the denominator, and join snapshots to events with an explicit as-of condition and a row-count check at each grain before aggregating.

Sizing safety stock as z times sigma_D times the square root of lead time

That form assumes lead time is deterministic. When lead time itself varies, the standard deviation of demand over lead time is sqrt(L_bar * sigma_D^2 + D_bar^2 * sigma_L^2), and the second term dominates whenever supply is unreliable, so the familiar formula can understate the requirement severalfold for a long, variable inbound lane. Two further preconditions are routinely forgotten: demand is assumed independent across periods, which promotions and order batching break, and z maps to cycle service level (the probability of no stockout in a replenishment cycle), not to fill rate, which additionally depends on order quantity through the unit normal loss function. Quoting a z-derived number as a fill rate overstates achieved service, and the gap widens as order quantity shrinks.

Extrapolating a first-week lift inflated by novelty effects

Plot the treatment effect by days since first exposure instead of quoting one pooled average. A lift that decays toward zero across the test window is behaviour that will not persist, and annualising it produces a forecast that misses by an order of magnitude.

Sizing estimates built on unnamed, unrevisable assumptions

Write each assumption as a named number you can change, then show the arithmetic so the interviewer can challenge one input instead of the whole answer. Finish by saying which assumption the result is most sensitive to, which matters more than the point estimate.

Questions & practice

How do you approach missing data imputation in predictive maintenance datasets without introducing systemic bias?

Medium · statistics and probability

Approach

  1. Quantify uncertainty explicitly rather than reporting a point estimate alone.
  2. Write down the assumption the method needs before you use the method.
  3. Sanity-check the answer against a simple bound or a simulated case.

Follow-up

  • How would you explain this result to someone who does not know statistics?
  • What sample size would you need to detect an effect half this size?

How would you design an A/B test for a new routing algorithm in our logistics supply chain software, and how do you determine the required sample size?

Medium · machine learning and modelling

Approach

  1. Say how the offline result would be validated online before it is trusted.
  2. Frame the prediction: the label, the moment of prediction, and the action it triggers.
  3. Set a baseline first, so any model has something honest to beat.

Follow-up

  • Where could label leakage enter this setup?
  • How would you choose the decision threshold, and who owns that choice?

Recover unconstrained demand from stockout-censored history

Hard · censoring · maximum likelihood · em algorithm

A legacy extract has only inventory_date, sku_id, location_id, shipped_qty and stockout_flag; demand_qty was not populated before a cutover date. On a stockout day, shipped_qty is a lower bound on that day's demand. Model daily demand per sku-location as Poisson and fit its mean by maximum likelihood, treating stockout days as right-censored observations. Return the fitted mean per cell alongside the naive mean of shipped_qty and the censored share. Then validate against the post-cutover window where demand_qty exists.

Approach

  1. Write the likelihood before any code. Uncensored days contribute the Poisson pmf at the observed count; stockout days contribute the survival probability P(X >= y), because all you learned is that demand was at least what you managed to ship.
  2. Solve it as an EM fixed point rather than reaching for a general optimiser: the censored MLE equals the complete-data mean with each censored observation replaced by its conditional expectation, so iterate lambda_next = (sum of uncensored y + sum of E[X | X >= y, lambda]) / n until it stops moving.
  3. Use the closed form for the conditional expectation rather than truncating an infinite sum: for a Poisson, sum over k >= y of k*p(k) equals lambda times P(X >= y-1), so E[X | X >= y] = lambda * P(X >= y-1) / P(X >= y) for y >= 1. That removes the tail-truncation error entirely.
  4. Refuse to fit cells with too little signal. A sku-location with three non-zero days or with every day censored has no identifiable mean; return the naive figure with a flag rather than a confident number.
  5. Validate on the post-cutover window where demand_qty is populated: fit the estimator on shipped_qty and stockout_flag alone, and compare both the censored estimate and the naive mean against the true mean of demand_qty.

Worked solution (45 min)

  1. Split each cell's days into censored (stockout_flag true) and uncensored, and record the censored share.
  2. Initialise lambda at the mean of shipped_qty over all days, which is a strict lower bound on the answer.
  3. Iterate the EM update using scipy.stats.poisson.sf for the survival terms, stopping when the change in lambda falls below 1e-8 or after 500 iterations.
  4. Assemble a per-cell frame with lambda_hat, naive_mean, censored_share, n_days and a converged flag; mark thin cells rather than fitting them.
  5. On the post-cutover window, compute the true mean of demand_qty per cell and report the absolute error of lambda_hat against the absolute error of naive_mean.

Expected result: Per-cell lambda_hat that is greater than or equal to the naive mean of shipped_qty in every cell, with equality exactly when the cell has no censored days. The uplift grows with censored share. On the validation window, lambda_hat has lower mean absolute error against the true demand_qty mean than the naive figure does.

Verify it yourself

  • Assert lambda_hat >= mean(shipped_qty) for every cell; the EM fixed point guarantees this because E[X | X >= y] >= y, so any violation is an implementation bug.
  • Re-solve one cell by directly minimising the negative log-likelihood with a one-dimensional optimiser and confirm it agrees with the EM answer to at least six decimal places.
  • Simulate a cell with known lambda, censor it artificially at a known threshold, and confirm the estimator recovers lambda within Monte Carlo error while the naive mean does not.
  • Confirm cells with zero censored days return lambda_hat exactly equal to the sample mean, since the likelihood reduces to the ordinary Poisson case.

Follow-up

  • The fitted mean is 18 percent above the naive mean for A-class items and 2 percent above for C-class. Why would you expect that ordering?
  • The residual variance is three times the fitted mean. What does that break and what distribution would you move to?
  • A stockout is often caused by a demand spike that day. What does that do to your estimate and can you correct it?

Write a SQL query using window functions to calculate running totals of equipment operating hours and identify monthly usage spikes.

Medium · sql and data manipulation

Approach

  1. Handle the rows that do not match: a LEFT JOIN with a NULL check is usually the question.
  2. Compute rates by summing numerator and denominator separately, never by averaging rates.
  3. State the window function and its partition and ordering out loud before writing it.

Follow-up

  • What breaks if events arrive late or out of order?
  • How does the query change if the join becomes one-to-many?

Optimize a slow-running SQL join query that aggregates daily equipment maintenance tickets across global regions.

Medium · sql and data manipulation

Approach

  1. Say which table is the grain you start from, and join outward from it.
  2. Handle the rows that do not match: a LEFT JOIN with a NULL check is usually the question.
  3. State the window function and its partition and ordering out loud before writing it.

Follow-up

  • How does the query change if the join becomes one-to-many?
  • How would you verify this result without re-running the same query?

As-of inventory position behind each short-shipped line

Medium · as-of join · window functions · lateral join

For every fct_order_line with line_status in ('shipped_short','backordered','cancelled_no_supply') and requested_ship_date in the last quarter, attach the inventory state that governed it: the fct_inventory_daily row for the same sku_id and ship_from_location_id with the greatest inventory_date strictly before requested_ship_date. Snapshots are taken at the location-local end of day. Return the line, ordered_qty, shipped_qty, and that snapshot's available_qty, blocked_qty, on_order_qty and in_transit_qty, plus the snapshot's age in days. Lines with no prior snapshot must appear with NULLs rather than disappearing from the result.

Approach

  1. Recognise the join is an inequality, not an equality. The snapshot is an end-of-day state, so the position that governed allocation is the last close strictly before the requested ship date, and the same-date row reflects the outcome rather than the cause.
  2. Implement it with LEFT JOIN LATERAL (SELECT ... WHERE sku_id and location_id match AND inventory_date < requested_ship_date ORDER BY inventory_date DESC LIMIT 1) ON TRUE, or equivalently ROW_NUMBER() OVER (PARTITION BY order_line_id ORDER BY inventory_date DESC) = 1 over a bounded candidate set.
  3. Bound the lateral with a floor such as inventory_date >= requested_ship_date - 14 so the scan does not walk the whole history for each line, and let that floor produce NULLs rather than silently dropping the line.
  4. Keep the join LEFT. Lines at a node with no prior snapshot are a data-quality finding worth counting, and an INNER join converts them into an invisible bias toward nodes with clean snapshot coverage.
  5. Check the row count before and after the join: the output must have exactly one row per order_line_id, and any excess means the as-of match is returning more than one candidate.

Worked solution (30 min)

  1. Filter fct_order_line to the three statuses and the quarter, and record the row count as the target.
  2. Attach LEFT JOIN LATERAL over fct_inventory_daily with the strict inequality, the fourteen-day floor, ORDER BY inventory_date DESC and LIMIT 1.
  3. Project the four quantity columns plus snapshot_age_days = requested_ship_date - inventory_date.
  4. Compare the result row count with the target; investigate any difference before aggregating anything.
  5. Count and group the NULL-snapshot rows by ship_from_location_id to see whether the gap is a node or a SKU launch artefact.

Expected result: Exactly one row per qualifying order_line_id, with snapshot columns drawn from the greatest inventory_date strictly less than requested_ship_date, snapshot_age_days at least 1, and NULL snapshot columns where no prior row exists inside the floor.

Verify it yourself

  • COUNT() of the result equals COUNT() of the filtered order-line set. Any excess is fan-out from a non-unique as-of match.
  • MAX(inventory_date) per line is strictly less than that line's requested_ship_date, with no equality cases.
  • The count of NULL-snapshot rows is small and attributable to specific nodes or newly launched SKUs rather than spread evenly.

Follow-up

  • Split the output by short_reason_code. Which codes should show available_qty at or near zero, and what does it mean when 'no_stock' lines show healthy availability?
  • blocked_qty is large on many of these lines. Is that a planning problem, and who owns it?
  • How would you extend this to the position at the moment of allocation rather than the previous close, and what would you need that the daily snapshot does not give you?

How would you design a product metric framework to track the health and reliability of connected heavy machinery?

Medium · product sense and metrics

Approach

  1. Decompose the metric into the rates that drive it, and say which one you would check first.
  2. Name one primary metric, then the guardrail that stops it being gamed.
  3. State what result would change your recommendation, so the answer is falsifiable.

Follow-up

  • How would you detect that the metric is being gamed rather than genuinely improving?
  • Which segment would you cut first, and what would that rule out?

If a key operational metric suddenly drops by fifteen percent week-over-week, walk through your step-by-step diagnostic framework to find the root cause.

Medium · product sense and metrics

Approach

  1. State what result would change your recommendation, so the answer is falsifiable.
  2. Fix the population and the time window before naming any metric.
  3. Name one primary metric, then the guardrail that stops it being gamed.

Follow-up

  • Which segment would you cut first, and what would that rule out?
  • How would you detect that the metric is being gamed rather than genuinely improving?

Explain the trade-offs between parametric and non-parametric testing methods when evaluating skewed machine performance metrics.

Medium · product sense and metrics

Approach

  1. Decompose the metric into the rates that drive it, and say which one you would check first.
  2. Fix the population and the time window before naming any metric.
  3. Restate the decision this analysis has to support, and who acts on the answer.

Follow-up

  • How would you detect that the metric is being gamed rather than genuinely improving?
  • What would you do if the primary metric and the guardrail moved in opposite directions?

How would you measure the success of a new predictive maintenance feature introduced to our dealer network portal?

Medium · product sense and metrics

Approach

  1. State what result would change your recommendation, so the answer is falsifiable.
  2. Name one primary metric, then the guardrail that stops it being gamed.
  3. Restate the decision this analysis has to support, and who acts on the answer.

Follow-up

  • How would you detect that the metric is being gamed rather than genuinely improving?
  • What would you do if the primary metric and the guardrail moved in opposite directions?

How do you test for statistical significance when your sample data contains extreme outliers typical of heavy equipment sensor failures?

Medium · a/b testing and experimentation

Approach

  1. Name the randomisation unit first; it decides the variance and what the test can detect.
  2. Decide the analysis before seeing data, including how long it runs and when you look.
  3. Say whether units interfere with each other, and switch design if they do.

Follow-up

  • What would you do if you could not randomise at all?
  • What would you conclude if the result is positive but the test is underpowered?

What are the most common experimentation pitfalls you watch out for when running concurrent tests on interconnected industrial machinery fleets?

Medium · a/b testing and experimentation

Approach

  1. State the primary metric and the minimum effect worth shipping, then size the test.
  2. Say whether units interfere with each other, and switch design if they do.
  3. Decide the analysis before seeing data, including how long it runs and when you look.

Follow-up

  • What would you do if you could not randomise at all?
  • How would you handle interference between treated and control units?

Diagnose a sample ratio mismatch in an order-line test

Easy · sample ratio mismatch · randomisation unit · collider bias

A promise-date algorithm was randomised 50/50 with the hash taken on order_id. Your analysis table has 180,000 fct_order_line rows in the window: 91,540 control and 88,460 treatment. Lines are excluded when line_status = 'cancelled_by_customer' or when the join to fct_shipment_leg on shipment_id returns no delivered leg. The readout shows treatment up 0.9 points on on-time delivery. Test the split, state what the result implies about the readout, and list the three most likely causes given how this table was built.

Approach

  1. Run the chi-square goodness-of-fit test against the designed 50/50 split: expected 90,000 per arm, deviation 1,540, so chi-square = 2 * 1540^2 / 90000 = 52.7 on 1 degree of freedom, p around 4e-13. That is not sampling noise, and the readout is not interpretable until it is explained.
  2. Check the grain mismatch first, because it is the cheapest explanation: assignment is on order_id but rows are lines. A perfectly balanced order split still yields unequal line counts whenever lines per order differ by arm, and a promise-date change that splits or consolidates orders does exactly that. Recount distinct order_id per arm before touching lines.
  3. Walk the filter chain and recount the ratio at every step: raw assignment log, then all lines, then after the cancelled_by_customer filter, then after the delivered-leg join. The step where the ratio breaks names the cause without any further argument.
  4. Recognise that both exclusions are post-treatment. Requiring a delivered leg conditions on an outcome the treatment moves, which opens a collider path: whichever arm ships more of the difficult lines retains more slow lines and is penalised for succeeding.
  5. Do not report the 0.9-point lift. Rebuild the metric with all assigned orders in the denominator and never-shipped orders scored as failures, then re-run and compare.

Worked solution (20 min)

  1. Compute the test: expected 90,000 per arm, deviation 1,540, chi-square = 2 * (1540^2 / 90000) = 52.7, p about 4e-13.
  2. Recount distinct order_id per arm on the raw assignment log, before any filter or join touches the data.
  3. Recount after each filter in the order the pipeline applies them, recording the arm ratio at each stage.
  4. If the raw order split is balanced, rebuild the readout at order grain with every assigned order in the denominator and unshipped orders counted as not on time.

Expected result: Chi-square 52.7 on 1 df, p about 4e-13: a genuine sample ratio mismatch, so the 0.9-point result is not reportable. The three causes to check, in order, are that the analysis grain (lines) differs from the assignment grain (orders), that the delivered-leg join drops lines at different rates by arm because shipping is itself an outcome, and that the cancellation filter removes post-treatment rows.

Verify it yourself

  • The z form must agree with the chi-square: a 0.856-point deviation over a 0.118-point standard error is 7.26, and 7.26 squared is 52.7.
  • A balanced order-level split alongside an unbalanced line-level split points straight at lines per order, so compare mean lines per order by arm directly.
  • Re-running with no post-assignment filters should move the 0.9-point effect; if it does not move at all, the imbalance sits upstream of the metric and the randomiser itself is suspect.

Follow-up

  • The split is clean at order_id but broken at line level. Is the readout salvageable, and at which grain would you report it?
  • How would you monitor for this automatically on a test that runs for six weeks, and at what threshold would you halt?

A seven percent demand rise that is a calendar artefact

Hard · seasonality · day-of-week · timezone

A planner reports regional demand up 7 percent for the most recent four weeks against the prior four and wants safety stock raised. fct_inventory_daily is cut at each node's local end of day using dim_location.timezone and working_calendar_id. The recent window contains one public holiday fewer and spans a daylight-saving transition. Using fct_inventory_daily (inventory_date, location_id, sku_id, demand_qty, stockout_flag), dim_location and dim_sku, test whether underlying demand moved at all. Deliverable: a calendar-adjusted growth figure and a statement of what you would raise, if anything.

Approach

  1. Count exposure before comparing totals, and be exact about what can differ. Any 28-day window contains exactly four of each weekday whatever date it is anchored to, so two consecutive four-week windows have identical weekday composition and a weekday-mix reweighting between them is identically zero. Assert it rather than assume it, then set it aside. The weekday term only becomes live when a window is not a whole multiple of seven days, which happens the moment someone compares calendar months or a truncated most-recent week, so the assertion is worth keeping in the query.
  2. What does differ is working days, and that is where the arithmetic lives. Derive each window's non-working dates per node from working_calendar_id: on a five-day calendar a 28-day window holds 20 weekdays, so one public holiday fewer takes a node from 18 working days to 19 (5.6 percent more selling exposure) or from 19 to 20 (5.3 percent), before any demand moves. Compare demand per working day, not demand per calendar day.
  3. Weight those days the way demand is actually distributed. Because order cut-offs are daily and local, days are not interchangeable: build a day-of-week index per node from 52 weeks of history with holiday dates excluded (mean demand_qty by weekday over the node's overall daily mean), and define exposure as the sum of that index across the window's working days. Demand per unit of index-weighted exposure is the adjusted figure; demand per plain working day is the cruder version and is wrong by the index spread whenever the holiday falls on an unusually heavy or light weekday.
  4. Measure the holiday's shoulder separately, because the exposure adjustment cannot see it. Orders that would have been placed on the closed day arrive on the working day before or after, so a window with one holiday fewer also loses the displaced spike its neighbours carried. Compare demand_qty on the two working days either side of each holiday against those weekdays' index values and report the displaced units as their own line.
  5. Bound the daylight-saving effect instead of arguing about it. The snapshot is cut at local end of day, so one inventory_date per timezone spans 23 or 25 hours: at most one extra or missing hour of order capture on one of 28 days, about 0.15 percent of the window even if that hour carried normal trading volume, which at an overnight transition it does not. Identify the transition date per timezone, compare its demand_qty against neighbouring same-weekday dates, and report growth with and without it so the term is shown to be small rather than presumed to be. Then test whatever residual survives against the same calendar weeks one year earlier under the identical exposure adjustment, and ask whether it is demand or the relaxation of censoring: an order never placed because the item displayed as unavailable leaves no row at all, so a window with fewer stockout days records higher demand_qty with underlying demand flat. Cut the residual by stockout_flag history per sku-location before calling it growth.

Follow-up

  • After adjustment the growth is 0.4 percent with a wide interval. What do you tell the planner, and what would change your answer?
  • Which of these adjustments would you bake into the standard report, and which stay manual because they need judgement?
  • If the residual is recovered censored demand rather than growth, does that argue for more safety stock or less?

Suggested practice checklist

For someone who can already write the query and train the model but stalls when asked what to measure or whether a change is worth making. Metric definition and case structure come first; the technical work is kept as maintenance rather than the centre of the week.

Day 1 — Metric anatomy

  • For three products you use daily, write one primary metric, two input metrics that plausibly move it, and one guardrail that would catch a cheap way of moving the primary at the cost of the product.
  • For one of them, specify the metric precisely enough that two analysts would return the same number: numerator, denominator, unit of observation, time window, and how returning and deleted accounts are treated.
  • Pick a ratio metric and write what happens to it when the denominator shrinks for reasons unrelated to the numerator, with a concrete example of that happening.

Deliverable: A one-page metric tree for one product, with the primary metric written as an unambiguous spec.

Day 2 — Diagnosing a drop without guessing

  • Take the prompt "weekly active users fell 8 percent week over week" and write the segmentation plan before proposing any cause: platform, region, tenure cohort, acquisition channel, and whether the movement sits in the numerator or in a changed denominator.
  • List the instrumentation failures that manufacture fake drops (a client release that stopped firing an event, a bot filter change, a shifted date boundary or timezone) and write the query that rules out each one.
  • Rehearse stating the boring explanations first, seasonality and day-of-week composition, before reaching for a product cause.

Deliverable: A drop-diagnosis checklist short enough to recite from memory in under a minute.

Day 3 — Should we build it

  • Take a feature idea and write it as a bet: what you believe is true, what would have to be true for it to pay off, the metric that would confirm it, and the effect size that would justify the engineering cost.
  • Size the opportunity top-down and bottom-up, then reconcile the two numbers in writing instead of quoting whichever is friendlier.
  • Write the counter-metric that would make you kill the feature even if it wins on the primary metric.

Deliverable: A one-page product memo ending in a decision rather than a list of considerations.

Day 4 — The places aggregate numbers lie

  • Construct a Simpson's paradox numerically: two segments where the treatment wins within each segment yet loses overall, and identify the shift in segment weights that causes it.
  • Take a heavy right-tailed quantity such as revenue per user and write why the mean is the wrong summary, which percentile you would report instead, and what a moving mean with a stable median tells you.
  • Write your definition of a session for the product from day one, then name two real behaviours it misclassifies.

Deliverable: One page holding a worked Simpson's paradox table and a session definition with its two known failure cases.

Day 5 — Technical maintenance, aimed at metrics

  • Solve four timed SQL prompts that all end in a ratio metric, so the question of grain stays live in every answer.
  • Compute a 95 percent confidence interval for a proportion on a small sample, and state why the normal approximation is unreliable when either np or n(1 minus p) falls below roughly 10, along with which interval you would use instead.
  • Take one metric from your day-one tree, write the query that computes it correctly, then write the query that computes it wrong in the most plausible way and explain how you would notice.

Deliverable: Four solved prompts plus a matched correct and plausible-wrong query for one metric.

Day 6 — Turning engineering work into data science stories

  • Write three project stories as situation, decision, trade-off, outcome, each carrying one number and one thing you got wrong.
  • For the story you will lead with, prepare an answer to "what would you do differently" that names a decision you made, not a constraint you were handed.
  • Practise the sentence that reframes a systems project as a question project: the question the work answered, ahead of the pipeline it shipped.

Deliverable: Three written stories with the lead story delivered aloud and timed under four minutes.

Day 7 — Mock case and gap list

  • Run a 40-minute mock case with someone playing a product manager who pushes back on your metric choice, and record it.
  • Listen back and mark every moment you proposed a solution before the success metric existed.
  • Rewrite those moments as the question you should have asked, and rehearse the first 90 seconds of the case until scoping comes before solving.

Deliverable: A recorded case plus a rewritten opening 90 seconds.

Ownership when the result is inconvenient

Sometimes the honest read is that the initiative did not work, and the person who commissioned the analysis was hoping otherwise. Interviewers want to know whether you softened it. Prepare the case where you delivered an unwelcome result, how you presented the uncertainty without hiding behind it, and what the team did next.

Tell me about a time when you had to manage conflicting priorities between data engineering teams and business stakeholders.

Medium · behavioural and stakeholder questions

Approach

  1. Pick a story where you drove the decision, not one where you observed it.
  2. Name the disagreement or constraint, and how you resolved it with evidence.
  3. State the situation in two sentences and spend the rest on your reasoning.

Follow-up

  • How did you know the outcome was caused by your change?
  • What would you do differently if you ran that project again?

Scope a vague request about rising inventory

Easy · scoping · stakeholder management · inventory turns

A planning director opens with: inventory is up twelve percent on flat shipments, get me an analysis by Friday. You have fct_inventory_daily (inventory_date, sku_id, location_id, on_hand_qty, standard_cost_cents) and fct_order_line (shipped_qty, unit_cogs_cents, requested_ship_date). Nothing else is specified: not the window, not the comparison basis, not whether the twelve percent is units or value. State the three questions you would ask before writing any SQL, name the decision each answer changes, and describe the first cut you would run if nobody answers you before Friday.

Approach

  1. Ask what decision hangs on the answer: a buy stop, a write-off provision, a policy review and a board slide all need different cuts, and the director usually has one of them in mind.
  2. Pin the measurement before the cause: units or value, which two windows are being compared, and whether the denominator is average daily on-hand or a period-end snapshot, since a month-end denominator biases turns high by ten to twenty percent and can manufacture the whole movement.
  3. Ask which part of the network is in scope, because echelon matters: a build at echelon 2 ahead of a promotion and a build of blocked_qty at a plant are different problems with different owners.
  4. Commit to a default if no answer arrives: value at standard cost, averaged across every daily snapshot in both windows, cut by echelon, then by abc_class and xyz_class, then by lifecycle_status to separate phase_out stock from active cover.
  5. Say out loud what the first cut cannot settle, so the director is not surprised: it localises the build but does not attribute it to forecast bias, a lot-size change or a supplier pulling orders in.

Follow-up

  • The build is concentrated in one product family at two DCs. What are your next two queries, and what would make you stop calling it a planning problem?
  • The director wants the number by Friday and the cause by Friday. Which do you drop, and how do you say so?

Defend a finding that the expedite program bought nothing

Medium · defending findings · counterfactual reasoning · landed cost

Over two quarters, expedite_premium_cents on outbound legs in fct_shipment_leg rose from 0.4 to 1.3 percent of landed cost, while perfect order rate moved from 91.2 to 91.5 percent, inside the week-to-week spread. The transport lead who sponsored the expedite program disputes the finding in a review in front of his director, arguing that your window contains a port disruption that would have made service worse without the spend. Present the finding, say what you concede on the spot, say what you hold, and name the evidence that would change your conclusion.

Approach

  1. Restate his objection in its strongest form before answering it, because a counterfactual worsening is a legitimate argument and treating it as an excuse ends the conversation.
  2. Separate what you measured from what you claimed: the data show no detectable service gain, not that expedite has no effect, and the difference is the entire argument.
  3. Test his hypothesis with the data you already have rather than defending in the abstract: split legs by exception_code = 'customs_hold' and by lane, and compare expedited against non-expedited legs on the same lanes in the same weeks, since if expedite were holding the line the expedited lanes should show a service gap over comparable non-expedited ones.
  4. Concede what is true: without a holdout you cannot rule out a protective effect, and the pre-period is contaminated by the disruption, so the honest statement is an upper bound on the gain rather than a zero.
  5. Hold the part that survives: the spend is real, it is concentrated in a small set of lanes, and nobody set a decision rule for when a leg gets expedited, which is a controllable problem independent of the counterfactual.
  6. Name the next measurement: a lane-level staggered switch-off with a stated burn-in, and say what it would cost and how long it would take.

Follow-up

  • He offers to run the switch-off only on his two best lanes. Why is that a problem, and what do you counter with?
  • His director asks you for a yes or no on cutting the budget today. What do you say?