cswork / libraryOpen practice workspace

Interview guides · DTE Energy

DTE Energy Data Scientist Interview Questions & Guide 2026

Practice explaining analysis before a DTE Energy data scientist interview: the recommendation, the uncertainty, the follow-ups.

The 60-second brief

As a Data Scientist at DTE Energy, you are at the forefront of the energy industry’s digital transformation. You don't just build models; you provide the analytical backbone for a company responsible for the energy needs of millions of residents and businesses across Michigan. Your work directly impacts grid reliability, renewable energy integration, and the overall customer experience, making you a critical asset in the transition toward a cleaner, more sustainable energy future.

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

  • Evaluate forecasts at the lag ordering actually uses
  • Trace an on-time miss to one node
  • Size safety stock under variable lead times

Overview

The problems you will solve are both high-stakes and high-complexity. From predicting equipment failure before it causes a power outage to optimizing load forecasting for a fluctuating grid, your insights drive operational efficiency and safety. You will work with massive, diverse datasets—including smart meter data, weather patterns, and infrastructure telemetry—to turn raw information into strategic business decisions.

Joining DTE Energy means entering a mission-driven environment where data science is applied to physical-world challenges. Whether you are improving customer service through sentiment analysis or helping the company reach its carbon goals, your contributions have a tangible impact on the communities DTE Energy serves. It is a role that requires a balance of rigorous statistical discipline and a pragmatic, solution-oriented mindset.

The DTE Energy interview process

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

Behavioral Screen

Behavioural answers from data candidates get audited in a way that answers from other roles do not. When you say a model lifted retention, the next question is the denominator, the window, and how you knew the lift was not seasonal. So attach the measurement to each claim while you tell it: what the metric was before, over what period, and against what comparison. Numbers with no baseline read as rounded-up memory, and one unsupported figure tends to make the rest of the story sound rehearsed.

What to demonstrate

  • Whether each impact number arrives with a baseline, a window and a comparison, or as a bare percentage
  • Whether you can name the method that attributed the effect to your work (an experiment, a staged rollout, a seasonal control) or concede the link was correlational
  • Whether the magnitudes stay internally consistent when the interviewer multiplies them against the scale you described earlier

How to prepare

  • For each story, write the impact line as metric, value before, value after, window, and how attribution was established. Any line missing two of those five is a follow-up you will answer badly.
  • Re-derive one headline number from the source table rather than the deck that reported it. Resume numbers drift upward across retellings.
  • Decide in advance which figures you cannot share, and prepare the ratio or relative change you can give instead, so a confidentiality limit does not read as evasion.

Technical Evaluations

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

Timed Case Study

This round runs as a working session, so part of what it decides is whether you are useful to think with. The interviewer will interrupt: a hint that the data you assumed does not exist, a challenge to your metric, a nudge toward a branch you skipped. Treating those as interference is the common failure. Reason out loud while your thinking is still provisional so there is something to react to, and when a redirect arrives, take it instead of defending the path you had already started down.

What to demonstrate

  • Whether your reasoning is audible while it is still unsettled, or only after you have privately decided
  • What you do with a hint: absorb it and adjust, or argue for the original route
  • Whether your clarifying questions have answers that would change your approach, as opposed to filling silence
  • Whether you can be wrong about something in the middle of the case and keep moving without restarting

How to prepare

  • Run practice cases with a partner instructed to interrupt twice: once to remove a data source you assumed existed, once to reject the metric you chose. Practise absorbing both without going back to the start.
  • Before each practice case, write down the clarifying questions you plan to ask, then check afterwards whether any answer actually changed what you did. Drop the ones that did not.
  • Explain an analysis you already know well to someone outside the field and have them stop you at every point where the reasoning jumped a step.

Interaction with Team

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

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.

Treating shipped units as demand

Shipments are censored at available inventory: on a stockout day the recorded quantity is a supply ceiling, not customer intent, and orders that were never placed because the item showed as unavailable leave no row at all. A forecast fitted on that history learns the constraint, under-forecasts the fast movers that stock out most often, and produces the replenishment that causes the next stockout, so the error compounds in one direction rather than averaging out. The fix is to model demand_qty rather than shipped_qty, flag stockout days with stockout_flag and treat them as censored (fit with a censored likelihood, or estimate unconstrained demand from uncensored periods and comparable locations), and to report how much of the history was censored alongside any accuracy number.

Over-explaining the method and under-explaining the implication

Lead with the answer and what you would do about it, then give the approach when asked. Roughly one sentence of method per three of implication is the right ratio for a stakeholder-facing answer; the interviewer already knows what a regression is.

Reading a dozen metrics with no multiplicity control

Nominate one primary metric before launch and treat the rest as guardrails or exploratory, with Bonferroni or Benjamini-Hochberg applied when you intend to make claims from them. Twenty independent tests at 0.05 under the null produce at least one false positive about 64 percent of the time.

Questions & practice

How do you stay current with the latest developments in machine learning and data science?

Medium · machine learning and modelling

Approach

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

Follow-up

  • How would you choose the decision threshold, and who owns that choice?
  • What would you monitor after launch to know the model is still valid?

What are the assumptions of a linear regression model?

Medium · machine learning and modelling

Approach

  1. Pick an evaluation metric that matches the cost of each error type, not a default.
  2. Frame the prediction: the label, the moment of prediction, and the action it triggers.
  3. Say how the offline result would be validated online before it is trusted.

Follow-up

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

As-of join snapshots to order lines without merge_asof

Medium · as-of join · fan-out · searchsorted

You have fct_order_line (order_line_id, sku_id, ship_from_location_id, actual_ship_at_utc, shipped_qty, shipment_id) and fct_inventory_daily (inventory_date, sku_id, location_id, available_qty). For every shipped line, attach available_qty from the latest snapshot strictly before the ship date for that exact sku and node, plus the shipment's delivery timestamp from fct_shipment_leg (leg_id, shipment_id, delivered_at_utc, leg_status). The output must have exactly one row per input order line. pandas.merge_asof is not available; implement the as-of match yourself.

Approach

  1. Collapse fct_shipment_leg to one row per shipment_id before joining anything. A shipment is one or more legs, so a direct line-to-leg join multiplies every line by its leg count and quietly inflates every sum computed afterwards.
  2. Define the shipment-level delivery as the maximum delivered_at_utc across its legs, and set it null if any leg is not delivered, since the customer has the order only when the last leg lands.
  3. Sort the snapshot frame by (sku_id, location_id, inventory_date) and the line frame by the same key plus ship date, then use np.searchsorted with side='left' on the sorted dates within each key group to find the insertion point; the matching snapshot is the row at position minus one.
  4. Guard the boundary explicitly: an insertion point of 0 means no snapshot exists before that ship date, and the result must be null rather than the first available future snapshot. Count those lines and report them.
  5. Assert the output row count equals the input line count immediately after each merge, before any aggregation. Row-count drift is the only symptom a silent fan-out produces, and it is invisible once the frame has been grouped.

Worked solution (30 min)

  1. Aggregate legs by shipment_id to produce delivered_at_utc as the max, leg_count, and a delivered_all flag from leg_status.
  2. Left join that one-row-per-shipment frame onto fct_order_line by shipment_id and assert the row count is unchanged.
  3. Sort snapshots and lines by the composite key, then compute per-group insertion points with np.searchsorted and subtract one.
  4. Mask positions below zero to null, take available_qty at the remaining positions, and attach it as available_qty_prior.
  5. Validate on a single sku-location pair by printing its snapshot dates and one line's ship date and confirming the chosen date by eye.

Expected result: A frame with exactly as many rows as the input order lines, carrying available_qty_prior (null for lines with no earlier snapshot), delivered_at_utc and leg_count, plus a printed count of unmatched lines.

Verify it yourself

  • Assert len(output) equals len(fct_order_line) after every join step, not only at the end.
  • Assert every non-null matched snapshot date is strictly less than the line's ship date, and that no snapshot date for the same key falls between the match and the ship date.
  • Compare against a slow brute-force loop over 200 sampled lines; the two must agree on every row.
  • Confirm the unmatched count equals the number of lines whose ship date precedes the first snapshot for their sku-location pair.

Follow-up

  • The snapshot is taken at the node's local end of day and actual_ship_at_utc is UTC. Where does that break the strictly-before rule and what do you need from dim_location to fix it?
  • How would you extend this to allocate each leg's linehaul cost back to the order lines it carried?
  • What changes if a line ships in two partial shipments?

Explain the difference between a LEFT JOIN and an INNER JOIN and when you would use each.

Medium · sql and data manipulation

Approach

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

Follow-up

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

Write a SQL query to find the second-highest energy consumer in each zip code.

Medium · sql and data manipulation

Approach

  1. State the window function and its partition and ordering out loud before writing it.
  2. Compute rates by summing numerator and denominator separately, never by averaging rates.
  3. Say which table is the grain you start from, and join outward from it.

Follow-up

  • How would you verify this result without re-running the same query?
  • What breaks if events arrive late or out of order?

Describe the process of feature selection for a high-dimensional dataset.

Medium · sql and data manipulation

Approach

  1. Check whether any join is one-to-many before aggregating, or the sums inflate.
  2. State the window function and its partition and ordering out loud before writing it.
  3. Compute rates by summing numerator and denominator separately, never by averaging rates.

Follow-up

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

Dead stock cells excluding SKUs used as substitutes

Medium · anti-join · null semantics · dead stock

Find dead stock: sku_id x location_id cells whose latest fct_inventory_daily row has on_hand_qty > 0 and which have no fct_order_line with that sku_id and ship_from_location_id in the last 90 days. Also exclude any SKU that filled another line as a substitute in that window; fct_order_line.substituted_sku_id is NULL on every line that was not substituted. Value each cell at on_hand_qty * standard_cost_cents taken from the snapshot, not from dim_sku. Return the cell, days since its last demand line, and value, ordered by value. Treat line_status = 'cancelled_no_supply' as demand.

Approach

  1. Take the latest snapshot per sku-location with ROW_NUMBER() OVER (PARTITION BY sku_id, location_id ORDER BY inventory_date DESC) = 1, or an equivalent MAX(inventory_date) join, and keep rows with on_hand_qty > 0.
  2. Anti-join demand with NOT EXISTS against fct_order_line on both sku_id and ship_from_location_id over the 90-day window, counting every line status including cancelled_no_supply, because unmet demand is still demand and a cell with it is not dead.
  3. Write the substitute exclusion as NOT EXISTS, or force substituted_sku_id IS NOT NULL inside the subquery. NOT IN over a column that contains NULLs evaluates to NULL for every candidate that is not an explicit match, so the predicate is never true and the result set is empty.
  4. Value from the snapshot's standard_cost_cents rather than dim_sku, since the dimension carries only the cost in force today and is revised at period close without back-dating.
  5. Get days since last demand from a LEFT JOIN LATERAL MAX(ordered_at_utc), and report cells that never had a line in a separate bucket instead of as a very large number.

Worked solution (30 min)

  1. CTE latest_snap: ROW_NUMBER over sku_id, location_id ordered by inventory_date DESC, filtered to rn = 1 and on_hand_qty > 0.
  2. CTE last_demand: MAX(ordered_at_utc) grouped by sku_id, ship_from_location_id over all of fct_order_line, with no status filter.
  3. Select from latest_snap LEFT JOIN last_demand, keeping rows where the max is NULL or older than 90 days.
  4. Add AND NOT EXISTS (SELECT 1 FROM fct_order_line o WHERE o.substituted_sku_id = latest_snap.sku_id AND o.ordered_at_utc >= now() - interval '90 days').
  5. Project value_cents = on_hand_qty * standard_cost_cents, order by it descending, and run the same query once with NOT IN to see the empty result for yourself.

Expected result: One row per dead sku-location cell with value_cents computed from the latest snapshot's own cost column, days_since_last_demand (or an explicit never-ordered bucket), ordered by value_cents descending. The substitute exclusion removes some rows; it must not empty the result.

Verify it yourself

  • Swapping NOT EXISTS for NOT IN on substituted_sku_id collapses the output to zero rows. That is the diagnostic for the NULL semantics, not a data finding.
  • Total value across returned cells is strictly less than total on-hand value at the same snapshot date.
  • No returned cell appears in SELECT DISTINCT sku_id, ship_from_location_id FROM fct_order_line over the same 90 days.

Follow-up

  • The query returns zero rows. Name the two likeliest causes and say which you would test first, with the one-line test.
  • How do you separate genuinely dead stock from a seasonal item out of season and from a lifecycle_status = 'pre_launch' SKU?
  • The same SKU is dead at one node and short at another. Write the query that finds that pattern and say what it implies about the policy.

If you were asked to predict transformer failure, what data sources would you look for?

Medium

Approach

  1. Work from the decision backwards to the evidence you would need.
  2. Say what you would check first and why it is the highest-information step.
  3. State your assumptions explicitly before working the problem.

Follow-up

  • What assumption would you test first?
  • How would you know your answer was wrong?

A fill rate that improves by cancelling what it misses

Easy · gameable metrics · denominator integrity · audit series

Unit fill rate is defined as SUM(shipped_qty) over lines shipped on or before requested_ship_date, divided by SUM(ordered_qty) over lines with requested_ship_date in the week, excluding lines with line_status = 'cancelled_by_customer'. A node is now paid on it. Using fct_order_line (line_status, short_reason_code, ordered_qty, shipped_qty, cancelled_qty, substituted_sku_id, ordered_at_utc, requested_ship_date, account_id, sku_id, ship_from_location_id), list the routes by which this number rises without service improving, and specify the audit series that detects each.

Approach

  1. Attack the denominator first: removing a line removes a miss, and the only exclusion the definition grants is customer cancellation, a status written by the same operation being scored.
  2. Name re-entry: a short line closed and re-keyed as a fresh order arrives with a new requested_ship_date, so the miss leaves the scoring window entirely instead of being cancelled inside it.
  3. Name intake suppression: a line never created because the item showed unavailable enters neither side of the ratio, which is the only route that leaves no trace in this table and therefore needs demand-side evidence to detect.
  4. Name numerator inflation: substitution counted as a fill without saying so, partial shipments credited at ordered_qty, and shipping early against a requested date that was itself edited.
  5. Attach one audit series to each route from the same table: weekly cancelled_by_customer share by node, share of accounts re-ordering the same sku within seven days of a cancellation, substitution share, and median hours from ordered_at_utc to terminal status.
  6. Close with the structural fix: publish cancellation mix beside the rate, and pair it with perfect order rate, so that cancelling an order cannot improve both numbers at once.

Worked solution (20 min)

  1. Compute the weekly fill rate per node by re-summing shipped_qty and ordered_qty, never by averaging line-level ratios.
  2. Compute cancellation mix beside it: cancelled_qty split by line_status in ('cancelled_by_customer','cancelled_no_supply') as a share of ordered_qty, per node per week.
  3. Compute the re-entry series: lines whose (account_id, sku_id, ship_from_location_id) reappears within seven days after a cancellation or a short ship.
  4. Compute substitution share and median hours from ordered_at_utc to terminal status, both by node and week.
  5. Quantify the exposure algebraically: moving x units of unmet demand out of the denominator takes a rate r to r divided by (1 minus x/D), then read that against normal week-over-week variation.

Expected result: Four named routes, each with its audit series, plus the arithmetic that sizes the exposure: excluding one percent of the denominator lifts a 95.0 percent fill rate to 95.96 percent, which exceeds a typical week-over-week swing, so any monitoring threshold has to sit well below a one-point move. The recommendation is to publish cancellation mix and perfect order rate alongside the headline rather than to tighten the definition alone.

Verify it yourself

  • The identity holds: denominator units equal shipped plus short plus backordered plus no-supply-cancelled units, with customer cancellations excluded and reported separately.
  • Recomputing after relabelling a share of cancelled_no_supply units as cancelled_by_customer reproduces the r divided by (1 minus x/D) formula to rounding.
  • A node improving genuinely shows a falling cancelled_no_supply share; a gamed one shows that share falling while cancelled_by_customer rises by a similar quantity in the same weeks.

Follow-up

  • Which of these routes still works if you score lines rather than units?
  • A node's cancelled_by_customer share doubled in one week. What confirms or clears it before you accuse anyone?

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

  1. 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.
  2. 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').
  3. 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.
  4. 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.
  5. 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

Four days spend equal time on query work, statistics, modelling and product judgement at deliberately shallow depth, which produces a scored map of where you actually stand. The last three days spend everything on the two areas the role weights most, and close by re-running day one to measure movement.

Day 1 — Breadth pass: query fluency

  • Solve six prompts spanning aggregation, joins, window functions and date arithmetic in 60 minutes total, stopping at 10 minutes each whether or not it works, and mark every prompt as solved, solved slowly, or stuck.
  • For each unsolved prompt write the single blocking sentence (I lost the grain, I did not know the frame clause, I could not express the date boundary) instead of reading the solution.
  • Translate one pandas transformation you know well into SQL and one SQL query into pandas, checking that both return the same row count and the same totals.

Deliverable: A scored six-row table, one line per prompt, saved for the day-seven re-run.

Day 2 — Breadth pass: statistics and inference

  • Answer ten short questions in writing with nothing open: what a p-value is conditional on, what a 95 percent interval covers across repeated samples, when a paired test is the right one, what the bootstrap estimates, why multiple comparisons inflate false positives, how controlling the family-wise error rate differs from controlling the false discovery rate, what power depends on, what a missed real effect costs a product, the three situations where the central limit theorem does not rescue you (small n, very heavy tails, dependent observations), and what a standard error is the standard deviation of.
  • Grade yourself against a reference and count only the answers that were exactly right, not the ones that were nearly right.
  • Rewrite the two weakest answers the following morning from memory in full sentences.

Deliverable: Ten graded answers with an honest count of exact hits.

Day 3 — Breadth pass: modelling

  • Take one tabular dataset end to end in 90 minutes: a leakage-safe split, a baseline that is not a model (majority class or historical mean), one regularized linear model, one gradient-boosted tree, and a single evaluation metric chosen before you look at any result.
  • Write why that metric fits the cost structure: precision at a fixed recall for alerting, calibration for anything feeding a price or a threshold, ranking metrics for retrieval, and note that area under the ROC curve is insensitive to class balance in a way that can flatter a rare-positive problem.
  • Name the leak you were most likely to introduce (an encoding fit on all rows before splitting, or a feature computed after the label's timestamp) and write the check that would have caught it.

Deliverable: A notebook whose first cell states the metric and the baseline, plus two lines on what beat what and by how much.

Day 4 — Breadth pass: product judgement

  • Answer three case prompts aloud at 15 minutes each, timing how long passes before you state a success metric.
  • For one case write the first segmentation you would run and the row counts you expect per segment, so that a tiny segment cannot quietly drive the conclusion.
  • Take a metric definition you did not write, from a public dashboard, a textbook, or documentation you already have open, and list every place two analysts implementing it would diverge: which rows the denominator admits, whether the unit is an account or a person, what the time window is anchored to, and what happens to data that arrives late. Then write the one question that would close the largest of those gaps.

Deliverable: Three recorded case answers plus an ambiguity list for a metric someone else defined, ending in the single question you would ask about it.

Day 5 — Depth, first area

  • Rank the four areas by how many bullet points in the role description each one covers, pick the top one, and spend the entire day inside it.
  • Work the six hardest problems you can find in that area and for each write the generalizable move you should have reached for first, rather than the answer.
  • Re-solve the two you failed the same evening with notes closed.

Deliverable: Six generalizable moves written as instructions to yourself, not as solutions.

Day 6 — Depth, second area, and the seam between them

  • Repeat the depth protocol on the second-ranked area with the same six-problem structure.
  • Construct one problem that requires both areas at once, for example a metric redefinition whose effect you must validate with a test whose readout you then have to query.
  • Solve your own combined problem end to end and note where the handoff between the two areas cost you time.

Deliverable: One combined problem, solved end to end, with the handoff failure written down.

Day 7 — Integration and re-measurement

  • Re-run the six prompts from day one under the same clock and compare both correctness and time.
  • Run a 60-minute mixed mock that moves between areas without warning, since switching cost is what breadth passes do not train.
  • Write the two areas you would still fail on, and the sentence you will use in the interview when you hit one of them.

Deliverable: A before-and-after score table plus a written plan for the two remaining gaps.

Your part, not the team's

Most data work is done by groups, so an interviewer has to work out which piece was yours. An answer that runs on 'we' for several minutes gets interrupted with a question about what you personally did, and by then the answer sounds defensive even when it is true. Mark your own contribution as you go, and name the parts that belonged to someone else instead of leaving them ambiguous. Keep a few specifics back as well, like the name of the metric or who actually objected, so a probe can be answered with something you had not already said.

Describe a time you had to pivot your approach mid-project due to new data or changing priorities.

Medium · behavioural and stakeholder questions

Approach

  1. State the situation in two sentences and spend the rest on your reasoning.
  2. Name the disagreement or constraint, and how you resolved it with evidence.
  3. Close with what you would do differently, concretely.

Follow-up

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

Describe a time you found a significant error in your analysis after presenting it. What did you do?

Medium · behavioural and stakeholder questions

Approach

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

Follow-up

  • What would you do differently if you ran that project again?
  • What did you decide not to do, and why?

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?