Interview guides · Dhl Supply Chain
Dhl Supply Chain Data Scientist Interview Questions & Guide 2026
Data scientist prep for Dhl Supply Chain candidates: drill A/B design, power and minimum detectable effect on original exercises.
The 60-second brief
As a Data Scientist at Dhl Supply Chain, you play a pivotal role in transforming vast amounts of data into actionable insights that drive business strategy and operational efficiency. This position is critical to optimizing logistics, enhancing supply chain processes, and improving customer service. You will work with cross-functional teams to analyze data patterns, develop algorithms, and implement predictive models that shape decision-making and influence outcomes across the organization.
SQL is seldom the hardest round and is often the one that eliminates people. The working bar is usually window functions, correct deduplication, and joins that do not silently fan out rows, rather than obscure syntax.
Focus areas
- Price a service-level change in working capital
- Separate true demand from censored, stocked-out sales
- Trace an on-time miss to one node
Overview
The complexity and scale of data handled at Dhl Supply Chain present unique challenges and opportunities. You will engage with advanced analytics technologies and methodologies to tackle real-world problems, contributing to solutions that impact global supply chain operations. Whether it's forecasting demand, optimizing routes, or enhancing inventory management, your work will directly affect how Dhl Supply Chain operates, ultimately leading to improved service levels and reduced costs.
This role not only requires technical expertise in data analysis and machine learning but also demands strategic thinking and collaboration skills. You will have the opportunity to work closely with product teams, engineers, and operations managers, making your contributions vital to the success of various projects that cater to clients and users worldwide.
The Dhl Supply Chain interview process
Dhl Supply Chain candidates report 4 rounds · ≈ 3-5 weeks. The stages below are what candidates describe, not a published process.
Preliminary Phone Screening
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
HR Interview
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.
Technical Interview
Much of what gets scored here happens out loud while you type. Nobody can see your reasoning inside a half-written query, so five silent minutes read as being stuck even when they are not. State the plan in plain language first: which tables, what grain you are aggregating to, and the one filter that defines the population. Then write it. The narration doubles as insurance, because a wrong plan gets caught early and cheaply while a wrong query gets caught at the end with no time left to redo it. A timed statistics section, where one exists, is a separate test with its own clock.
What to demonstrate
- Whether the query you write matches the plan you just described
- What you do with a hint, meaning whether the correction gets absorbed or the first approach gets defended
- Whether you can debug your own wrong output by reading the result set and naming which part of the query produced the anomaly
How to prepare
- Solve three problems while screen-sharing into a recording, then watch it back and mark every stretch longer than thirty seconds where you said nothing
- Practise compressing the plan into one sentence before typing, then check afterwards whether the finished query actually matched it
- Time yourself on statistics questions that carry a business reading, such as what a confidence interval does and does not claim, rather than re-reading notes without a clock
Case Study Presentation
Underneath the business framing, this round is usually asking whether you can turn a fuzzy goal into a quantity that could be computed from data such a business would plausibly hold. That means a metric with a stated numerator, denominator, eligibility rule and time window, plus an honest account of the conditions under which it would mislead you. Answers come apart when a candidate names a familiar metric and never defines it, because every follow-up then lands on an ambiguity that was left open and the candidate has to invent the definition under pressure.
What to demonstrate
- Whether a named metric arrives with its denominator, eligibility rule and window attached rather than assumed
- Whether the measure follows from the mechanism you proposed, or is a recognisable metric retrofitted to it afterwards
- Whether you name a guardrail that would reveal the gain came from somewhere you did not want it to come from
- Whether you can say what data the plan requires and what you would settle for if that logging were never implemented
How to prepare
- Take five metrics you reach for by reflex and write each as one sentence containing numerator, denominator, eligibility rule and time window. The ones you cannot finish are the ones that will fail under follow-up.
- For a product you use daily, write the measurement plan you would propose for a change to it: primary metric, one guardrail, the unit of analysis, and the table the numbers would come from.
- Practise the substitution question. For three metrics you like, write what you would measure instead if the event you depend on were not being logged.
Where candidates lose points
Attributing demand variability to the node where it is observed
Order variance amplifies as it moves upstream: batching to a truckload, minimum order quantities, forecast-driven ordering and promotional pull all convert smooth end demand into lumpy replenishment orders, so a plant can see a coefficient of variation several times that of the underlying consumption. Diagnosing the plant's schedule instability as a plant problem then produces interventions that cannot work, because the generating process sits one or two echelons downstream. Measure the bullwhip ratio explicitly (variance of orders placed by a node over variance of demand it received) at each echelon, and fix the ordering rule at the node where the ratio jumps rather than the node where the pain is felt.
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.
Optimising accuracy on a heavily imbalanced target
State the base rate first, then choose the metric from the relative cost of a false positive against a false negative: precision and recall at the operating threshold, PR-AUC, or expected cost. At a 1 percent positive rate, predicting the majority class for everyone scores 99 percent accuracy and is worthless.
Naming a model class before naming the deployment constraints
Set out the latency budget, the label delay, the retraining cadence, the interpretability requirement and the number of labelled examples, then pick the model that fits them. A boosted-tree answer to a problem where each decision must be explained to the affected user is a well-executed answer to the wrong question.
Questions & practice
Explain how you would approach feature selection in a machine learning model.
Medium · machine learning and modelling
Approach
- Set a baseline first, so any model has something honest to beat.
- Frame the prediction: the label, the moment of prediction, and the action it triggers.
- Pick an evaluation metric that matches the cost of each error type, not a default.
Follow-up
- What would you monitor after launch to know the model is still valid?
- Where could label leakage enter this setup?
Write a function to implement a linear regression model in Python.
Medium · machine learning and modelling
Approach
- Pick an evaluation metric that matches the cost of each error type, not a default.
- Set a baseline first, so any model has something honest to beat.
- Check what information would not exist at prediction time, and exclude it.
Follow-up
- What would you monitor after launch to know the model is still valid?
- How would you choose the decision threshold, and who owns that choice?
Reconstruct replenishment cycles from a daily inventory series
Medium · event sessionisation · state reconstruction · lead time
For one sku-location you have a daily series: inventory_date, on_hand_qty, in_transit_qty, on_order_qty, allocated_qty, shipped_qty, demand_qty, reorder_point_qty, stockout_flag. There is no purchase-order table. Infer the replenishment cycles: a cycle opens on the first day inventory position falls to or below reorder_point_qty, and closes on the first subsequent receipt. Receipts must be inferred from the series itself. Return one row per cycle with trigger date, receipt date, inferred lead time in days, demand during the cycle and stockout days, then report mean and standard deviation of the inferred lead time.
Approach
- Derive the receipt signal from the stock balance rather than looking for a column that does not exist: on_hand today equals on_hand yesterday plus receipts minus units shipped, so implied_receipt = on_hand_qty.diff() + shipped_qty, and a positive value means goods arrived.
- State what else can make that quantity positive: a cycle-count adjustment, a customer return, or a scrap reversal. Corroborate each candidate receipt with a matching fall in in_transit_qty on the same or adjacent day, and discard the ones with no corroboration.
- Debounce arrivals. A load split across two dock shifts produces positive implied receipts on consecutive days; collapse runs of receipt days separated by less than a chosen gap into a single arrival and make the gap an explicit parameter.
- Compute inventory position as on_hand + in_transit + on_order - allocated, not on hand alone, or every day after a trigger looks like another trigger and the cycle count explodes.
- Walk the series once with an explicit state variable (awaiting-trigger, awaiting-receipt) rather than trying to vectorise the pairing. The state machine is what makes cycles non-overlapping, and it is what a reviewer can check line by line. Be clear that cycles defined this way do not tile the calendar: the stretch from a receipt until the position next falls to the reorder point sits inside no cycle.
Worked solution (35 min)
- Sort by inventory_date, assert no duplicate dates and no calendar gaps, and compute position = on_hand_qty + in_transit_qty + on_order_qty - allocated_qty.
- Compute implied_receipt = on_hand_qty.diff() + shipped_qty and mark receipt days where it is positive and in_transit_qty fell.
- Collapse consecutive receipt days into single arrivals using a gap threshold of one day.
- Iterate the series with a two-state machine, emitting a cycle row when a trigger is followed by an arrival, and carrying an open trigger forward across days.
- For each cycle sum demand_qty and stockout_flag between trigger and receipt, then compute mean and standard deviation of the lead times across cycles.
Expected result: A cycle table with non-overlapping intervals ordered in time, each with receipt_date strictly after trigger_date, plus two scalars: mean inferred lead time and its standard deviation across cycles. The cycles cover only the trigger-to-receipt stretches, so they will not add up to the length of the series; the post-receipt stretches where stock is still above the reorder point are outside every cycle by definition.
Verify it yourself
- Assert no two cycles overlap and that every receipt_date is strictly later than its trigger_date.
- Partition the calendar into four exhaustive categories and sum demand_qty over all of them: cycle days (trigger to receipt), post-receipt gap days (receipt to the next trigger), the head before the first trigger, and the tail after the last receipt. The total must equal total demand_qty. Summing cycles plus head and tail alone under-counts by exactly the gaps, which is the arithmetic proof that cycles do not tile the series.
- Confirm the day counts of those same four categories sum exactly to the number of days in the series. A shortfall means two cycles overlap or a boundary day is double-counted. Cycle count times mean cycle length is not a substitute for this check, since it ignores the gaps.
- Confirm total inferred receipts across the window approximately equals total shipped_qty plus the change in on_hand_qty from first day to last.
Follow-up
- Two orders are open at once because the trigger fired again before the first arrived. How does your state machine change?
- The policy quotes lead time in working days. What do you need from dim_location to convert, and where does the timezone matter?
- You now have mean and standard deviation of lead time. Write the safety stock this implies and say which assumption you are least comfortable with.
How would you optimize a SQL query for better performance?
Medium · sql and data manipulation
Approach
- State the window function and its partition and ordering out loud before writing it.
- Say which table is the grain you start from, and join outward from it.
- Handle the rows that do not match: a LEFT JOIN with a NULL check is usually the question.
Follow-up
- What breaks if events arrive late or out of order?
- How would you verify this result without re-running the same query?
Stockout streaks of three days or more per cell
Medium · window functions · gaps and islands · stockout analysis
fct_inventory_daily carries one row per sku_id x location_id x inventory_date for every active pair, including days with nothing on hand, plus stockout_flag marking days where available_qty reached zero. Return every run of consecutive stockout days lasting three days or more: sku, location, start date, end date, run length, and demand_qty summed across the run. Return alongside it, per sku-location, the count of such runs in the window. Verify that the daily row series is contiguous for each pair before relying on date arithmetic, and say what you do about pairs that fail.
Approach
- Filter to stockout_flag = TRUE, then assign ROW_NUMBER() OVER (PARTITION BY sku_id, location_id ORDER BY inventory_date).
- Form the island key as inventory_date - rn * INTERVAL '1 day'. Two rows share a key only when their dates are exactly consecutive, so the key cannot weld separate runs together; the exposure runs the other way. A day with no snapshot row inside a true stockout breaks that run into fragments, and any fragment under three days is deleted by the threshold, so the run leaves the output rather than appearing with a wrong length.
- Prove contiguity before trusting the key: per sku-location compare COUNT(DISTINCT inventory_date) against (MAX(inventory_date) - MIN(inventory_date) + 1), and separately confirm no pair carries two rows on one date, since a duplicate date advances rn without advancing the calendar and shifts every key after it. Pairs that fail get a generated date spine: LEFT JOIN generate_series over the window so each day is labelled stockout, in stock, or no snapshot, then apply a stated rule for the no-snapshot days instead of letting the key make that call silently. The conservative rule is to break the run at the hole and mark both fragments gap_adjacent.
- Group by sku, location and island key for MIN and MAX date, COUNT(*) as length and SUM(demand_qty) as the demand exposed to the stockout, keeping runs of length >= 3.
- Aggregate once more per sku-location for the run count, and mark runs touching either window edge as censored, since their true length is unknown from this window alone.
Worked solution (30 min)
- CTE completeness: per sku_id, location_id compute COUNT(DISTINCT inventory_date) and the date span, and flag pairs where they disagree or where COUNT(*) exceeds COUNT(DISTINCT inventory_date).
- CTE flagged: SELECT the stockout rows with ROW_NUMBER partitioned by sku_id, location_id ordered by inventory_date.
- CTE islands: add grp = inventory_date - rn * INTERVAL '1 day'.
- GROUP BY sku_id, location_id, grp producing MIN, MAX, COUNT() and SUM(demand_qty); filter COUNT() >= 3.
- Second aggregate over that result for runs per sku-location, plus a censored flag where start equals the window start or end equals the window end.
Expected result: One row per qualifying run with start_date, end_date, length and summed demand_qty, every length at least 3, plus a per-cell run count whose sum across cells equals the number of run rows returned. Length, end_date - start_date + 1 and the island's row count agree by construction of the key, so their agreement is not evidence that the runs are real.
Verify it yourself
- Every gap between two consecutive returned runs for the same sku-location contains at least one day carrying a snapshot row with stockout_flag = FALSE. A gap made only of days with no snapshot row is a hole rather than a recovery, and those two runs are likely one run the key split.
- The completeness CTE flags zero pairs. Where it flags any, that pair's run lengths and run count are lower bounds and must be labelled as such, not published beside clean pairs as if comparable.
- Total stockout days across all returned runs is less than or equal to the total count of stockout_flag rows in the window.
Follow-up
- The longest runs cluster on X-class A items. What does that combination suggest to look at before touching the safety stock policy?
- How would you estimate lost demand across a run, given that demand_qty records the orders that were placed but not the orders nobody bothered to place?
- The snapshot is taken at each location's local end of day and the pairs span several timezones. What breaks, and what stays true?
How would you approach optimizing a logistics network with multiple variables?
Medium · product sense and metrics
Approach
- State what result would change your recommendation, so the answer is falsifiable.
- Restate the decision this analysis has to support, and who acts on the answer.
- Name one primary metric, then the guardrail that stops it being gamed.
Follow-up
- What would you do if the primary metric and the guardrail moved in opposite directions?
- Which segment would you cut first, and what would that rule out?
If tasked with reducing delivery times, what data points would you analyze?
Medium · product sense and metrics
Approach
- Fix the population and the time window before naming any metric.
- State what result would change your recommendation, so the answer is falsifiable.
- Decompose the metric into the rates that drive it, and say which one you would check first.
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?
Given a dataset of customer transactions, how would you identify patterns in purchasing behavior?
Medium · product sense and metrics
Approach
- State what result would change your recommendation, so the answer is falsifiable.
- Name one primary metric, then the guardrail that stops it being gamed.
- 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?
- Which segment would you cut first, and what would that rule out?
How do you prioritize tasks when managing multiple projects?
Medium · product sense and metrics
Approach
- Decompose the metric into the rates that drive it, and say which one you would check first.
- State what result would change your recommendation, so the answer is falsifiable.
- Restate the decision this analysis has to support, and who acts on the answer.
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?
Describe how you would design an A/B test for a new supply chain process.
Medium · a/b testing and experimentation
Approach
- Name the guardrails that would stop a launch even on a positive primary result.
- Decide the analysis before seeing data, including how long it runs and when you look.
- 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?
- How would you handle interference between treated and control units?
Discuss a complex dataset you worked with and the insights you derived.
Medium
Approach
- Say what you would check first and why it is the highest-information step.
- Clarify what is being asked and what a complete answer would contain.
- Work from the decision backwards to the evidence you would need.
Follow-up
- How would you know your answer was wrong?
- What assumption would you test first?
Measure the demand that never becomes an order line
Hard · censored demand · proxy bias · unobservable metrics
Commercial asks for lost sales by SKU and node. fct_order_line records short-shipped lines (short_reason_code = 'no_stock') and no-supply cancellations, and fct_inventory_daily carries demand_qty, available_qty and stockout_flag, but an order a customer never placed because the item showed unavailable leaves no row anywhere. Define the metric you will publish, the proxy it rests on, the direction and likely size of its bias, and the guardrail that stops the proxy being quoted as a measurement.
Approach
- Separate observable from unobservable in writing. Short-shipped units with short_reason_code = 'no_stock' and cancelled_qty on lines with line_status = 'cancelled_no_supply' are recorded demand that went unmet. Demand that never became a line is absent from the schema at every grain, so no query returns it and no join recovers it.
- Publish the observable part under its own name, unmet recorded demand, and refuse to call it lost sales, because the two quantities differ by exactly the amount nobody can see.
- Build the proxy from uncensored periods: per sku-location, estimate a baseline demand rate from days where stockout_flag is false and available_qty stayed comfortably above that day's demand, adjust for day of week and season, impute the censored days, and take the excess over recorded demand.
- State the bias and its direction. The estimate is a lower bound, because purchases diverted before an order was keyed and demand absorbed by substitution onto another SKU are both invisible. The shortfall is largest on the SKUs with the most stockout days, so it correlates with the quantity being measured and cannot be treated as noise that averages out.
- Bound the size instead of asserting it: report the censored share of sku-location-days, and run the imputation on a holdout of uncensored days that you censor artificially, so the recovery rate is measured on data where the truth is known.
- Put the guardrail on use rather than on the number: any spend justified by this metric must still hold when restated on the observable part alone, otherwise the proxy is carrying the argument and should be labelled as doing so.
Worked solution (40 min)
- Quantify the censoring: share of sku-location-days with stockout_flag true, and share of ordered units on lines with short_reason_code = 'no_stock' or line_status = 'cancelled_no_supply'.
- Compute the observable metric: unmet recorded demand in units and at unit_price_cents, weekly by node and ABC class.
- Fit the baseline rate on uncensored days only, with day-of-week and week-of-year terms, pooled within ABC/XYZ class where a sku-location series is too thin to fit alone.
- Impute the censored days, take the gap, then hold out a random sample of uncensored days, censor them artificially at plausible availability levels, and measure what fraction of known demand the method recovers.
- Publish both series with the censored share and one written sentence naming what the proxy cannot see.
Expected result: Two published series rather than one: unmet recorded demand, which is computable and exact, and estimated unconstrained demand, which is modelled and is a lower bound. The bias statement records that the gap understates true demand because pre-order diversion and substitution are invisible, and that the understatement is largest on high-stockout SKUs, so the metric is least reliable precisely where it is most consequential. The holdout recovery rate is quoted as the only empirical evidence for the imputation.
Verify it yourself
- Estimated unconstrained demand is at least recorded demand on every sku-location-day; a cell below it means the baseline was fitted on censored days.
- The artificial-censoring holdout recovers a stated fraction of known demand; recovery near 100 percent means the artificial censoring was milder than real stockouts and the test is not informative.
- Excluding stockout days from the baseline fit changes the baseline; if the number does not move, the filter is not being applied.
Follow-up
- substituted_sku_id records substitutions. How much of the gap does it close, and what does counting it break in the donor SKU's own demand history?
- How do you use the imputed series in a forecast without letting the imputation feed its own next round?
Perfect order rate falls only in the newest two weeks
Medium · right censoring · reporting lag · metric maturation
A weekly perfect order chart holds at 94 percent for eleven weeks, then reads 91 percent and 84 percent in the two most recent weeks. The metric requires every line shipped_full, actual_delivery_at_utc on or before original_promised_delivery_date, and no joined shipment leg carrying exception_code IN ('damage','address_issue') or leg_status IN ('refused','lost'). It is published on a 14-day lag. Using fct_order_line and fct_shipment_leg, decide whether service regressed and specify what the chart should show for incomplete weeks.
Approach
- Start from the structure of the metric: the denominator is fixed at promise date while the numerator requires an event that may not have happened yet, so any week younger than the full delivery-plus-claims window is mechanically depressed. Establish that before hunting for a cause.
- Quantify the incompleteness instead of assuming it. Per promise week, report the share of lines with actual_delivery_at_utc IS NULL and the share of shipments whose legs are still leg_status IN ('tendered','in_transit').
- Build the maturation curve from history. For each of the eleven settled weeks, recompute the metric as it would have looked at 3, 7 and 14 days after the promise date, so a recent week can be compared against a healthy week at the same age rather than against a settled one.
- Only after age-matching, test whether any residual is real by cutting it by ship_from_location_id, mode and exception_code, and asking whether the loss concentrates where a genuine failure would concentrate.
- Fix the chart rather than only the analysis: suppress or grey weeks younger than the publication lag, or publish an age-matched estimate with an interval, and write the rule down so the next reader is not caught by the same shape.
Follow-up
- Damage claims can arrive up to thirty days later. Does that argue for a longer lag or for a different numerator?
- How would you detect a genuine regression inside the lag window without waiting two weeks for it to settle?
- P90 order cycle time shows the same maturation shape but biased the other way. Why, and which metric is more dangerous to read early?
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.
Being wrong in public
A number you shipped turned out to be wrong, and someone had already acted on it. That is one of the most useful stories a data person can carry. What is being scored is how fast you noticed, who you told first, and what you changed in the process so the same class of error could not repeat quietly.
What motivates you in your work as a data scientist?
Medium · behavioural and stakeholder questions
Approach
- Close with what you would do differently, concretely.
- Name the disagreement or constraint, and how you resolved it with evidence.
- Pick a story where you drove the decision, not one where you observed it.
Follow-up
- What would you do differently if you ran that project again?
- How did you know the outcome was caused by your change?
Prioritise transport, plant and commercial in one week
Medium · prioritisation · stakeholder management · decision value
Three requests land in the same week. Transport wants landed cost per delivered unit split by lane and mode from fct_shipment_leg for a carrier bid that closes in nine days. A plant manager wants OEE on two work centres decomposed into availability, performance and quality from fct_production_run for a capital request due next month. Commercial wants a fill-rate root cause from fct_order_line for an account review on Thursday. You are the only data scientist and have about four working days. Give your order, the rule that produced it, and what you say to the two who wait.
Approach
- Rank by the decision each request feeds and by whether your input can still change it, not by seniority or by who asked loudest: a bid closing in nine days is a live decision with a large irreversible spend attached, a capital request due next month has slack, and an account review has a fixed date but a smaller reversible decision.
- Check reversibility and blast radius: carrier rates lock for a contract period across every lane, so an error or an absence there is expensive for a year, while the fill-rate story can be revised next week.
- Look for the cheap partial that unblocks someone else: the fill-rate cut by node, by short_reason_code and by week is a few hours of work and covers most of what commercial needs on Thursday, so it does not have to wait behind the bid.
- Sequence with explicit time boxes: the commercial cut first because it is short and date-locked, the lane and mode cost analysis next with the allocation basis for multi-stop loads stated up front, and the OEE decomposition scheduled into the following week with a date the plant manager can hold you to.
- Tell the plant manager directly and early, with a date rather than a maybe, and say what you need from him in the meantime so the delay produces something.
- Escalate the trade-off rather than absorbing it silently: your manager should know a capital request slipped a week, because that is a business choice and not yours alone to make.
Follow-up
- The plant manager escalates and his director asks you to reorder. What do you do?
- Which of the three would you push back on entirely, and what would you offer instead?
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
- 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.
- 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.
- 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.
- 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.
- 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?