cswork / libraryOpen practice workspace

Interview guides · Delta Air Lines

Delta Air Lines Data Scientist Interview Questions & Guide 2026

Diagnose a metric move for Delta Air Lines data scientist prep: split by segment, rule out a logging change, separate mix shift from behaviour.

The 60-second brief

As a Data Scientist at Delta Air Lines, you are at the intersection of global logistics, complex operations, and premium customer experience. You are not just building models; you are solving high-stakes problems that impact millions of travelers and the efficiency of a massive, interconnected fleet. Whether optimizing flight scheduling, enhancing maintenance predictive models, or personalizing the passenger experience through machine learning, your work directly influences Delta Air Lines' reputation for operational excellence and innovation.

If the team owns experimentation, expect depth past a two-sample test: minimum detectable effect and its roughly inverse-square-root dependence on sample size (holding power, significance level and variance fixed), variance reduction from pre-period covariates, interference between units, and when a sequential design is the right call.

Focus areas

  • Cohort bookings on stay date, not booking date
  • Compute occupancy from sellable nights, never property averages
  • Separate cancelled, no-show and completed booking states

Overview

The role is deeply analytical and highly collaborative. You will be expected to translate ambiguous commercial questions into structured statistical or optimization problems, bridging the gap between raw data and actionable business strategy. Because Delta Air Lines operates in a highly regulated and high-frequency environment, the ability to build robust, scalable, and secure AI solutions is paramount. You will work alongside data engineers, product teams, and operational experts to ensure that your insights move from a research environment into production-grade, reliable services.

The Delta Air Lines interview process

Delta Air Lines candidates report 5 rounds · ≈ 4-6 weeks. The stages below are what candidates describe, not a published process.

Recruiter Screening

Most candidates lose this call inside the first two minutes, during the walkthrough of their own background. The account runs chronologically, sits at the level of tools and titles, and never arrives at a decision anyone could have disagreed with. Anchor on a problem instead of a timeline: what the team could not answer, what you did about it, what happened next. Ninety seconds is enough, and stopping on time leaves room for the half of the call that belongs to you. What you ask about how work gets prioritised signals your level more reliably than the walkthrough does.

What to demonstrate

  • Whether your background summary has a shape (problem, decision, consequence) or is a chronological list of tools and employers
  • Whether you can account for gaps, short stints and the reason you are looking, unprompted and without hedging
  • The substance of the questions you ask back, which an experienced screener reads as a level signal

How to prepare

  • Time your opening walkthrough against a clock. If it runs past two minutes, compress the earliest role into a single clause and spend the recovered time on the most recent one
  • Write one honest sentence for every gap or short stint visible on your resume and offer it before being asked about it
  • Prepare questions about how work arrives and gets prioritised: who writes the request, how often priorities change, and what happens to an analysis after it is delivered

Online Assessment

A handful of shapes account for most of what gets asked in this format: a ranking or deduplication inside groups, a running or rolling total, a period-over-period comparison, and a cohort tracked forward over time. Recognising the shape quickly is most of the speed here; deriving it from scratch while a clock runs is where the time goes. Know that a window function keeps every row while a GROUP BY collapses them, and know which one the question needs. If the exercise is in Python instead of SQL, the same shapes arrive as groupby with transform, shift and merge, and the same grain mistakes are available.

What to demonstrate

  • Whether you reach the right construct without a detour, such as ROW_NUMBER over a partition to deduplicate instead of a self-join against a MAX subquery
  • Whether you know what your window frame actually is, since adding ORDER BY inside OVER changes the default frame and silently changes a running total
  • Whether the thing runs. A near-miss that throws an error scores below a plainer query that returns the right rows.

How to prepare

  • Write each of the four shapes once from memory against a small schema and keep the working version somewhere you will reread it: dedupe with ROW_NUMBER, a running total, a month-over-month change with LAG, and a retention table
  • Compute one running total twice on data with tied timestamps, once on the default frame and once with ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, and look at where the two disagree
  • If Python is on the table, rebuild the dedupe and the running total with groupby and cumsum, then assert the two implementations return identical rows

Technical Interviews

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

Take-Home Case Study

Your submission is read asynchronously by someone who cannot ask you a clarifying question, and who will usually skim it before reading it properly. That changes what good looks like. The conclusion belongs near the top with the supporting analysis beneath it, and the code should run start to finish on a clean machine without a manual step you forgot to document. A reviewer forced to reconstruct your reasoning from the order of notebook cells is already discounting the work. The submissions that land are the ones where a busy reader gets the answer immediately and can verify it if they want to.

What to demonstrate

  • Whether the answer arrives before the methodology, so a reader who stops after the first page still has the recommendation
  • Whether the code runs end to end from the submitted files, with dependencies and data paths declared rather than assumed
  • Whether each chart is legible on its own, carrying axis labels and units, and exists to support a claim made in the text

How to prepare

  • Restructure a past analysis so the opening paragraph holds the recommendation and the number behind it, then check that nothing later in the document quietly contradicts it
  • Copy your own submission into an empty directory, run it in a clean environment, and fix everything that breaks; hidden local state is caught here or by the reviewer
  • For every chart, write the one sentence it is meant to prove, and delete the chart if you cannot write that sentence

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

Where candidates lose points

Running per-user experiments on shared, finite inventory

Independence between units fails when they compete for the same rooms on the same dates: a unit booked by a treatment user is removed from the control users' result sets, so the control arm is degraded by the treatment and the measured lift is inflated, sometimes to the point where a neutral change reads as a clear win. The effect is largest exactly where it matters most, in constrained markets and peak dates, and it is invisible in the usual diagnostics because both arms look balanced on pre-period covariates. Supplier-side treatments have the same problem in reverse, since a pricing or ranking change applied to some inventory changes the alternatives that every traveller sees. Randomise at the level that contains the competition, which is normally market-by-stay-week or a switchback on a market, and power the test on the number of clusters, not the number of users.

Using the search as the demand unit when the trip is the demand unit

One trip intent generates dozens of searches over days, across devices, mostly while logged out, and the number of searches per intent is a property of the interface rather than of demand. Any product change that encourages comparison or re-sorting inflates the denominator, so look-to-book falls while the product improves, and a change that reduces re-searching raises the metric while nothing about demand moved. The logged-out majority also means traveller_id is NULL for most early-funnel rows, so joining searches to bookings on traveller_id silently drops the part of the funnel you were trying to measure. Collapse on trip_intent_key first, then count, and report searches per intent separately as a diagnostic rather than letting it sit inside a conversion rate.

Interpreting a change before checking data quality and logging

Spend the first pass on row volume by day, null rates, duplicate keys, and whether the step change lands on a release or tracking-migration date. A discontinuity that coincides with a deploy is an instrumentation hypothesis before it is a behavioural one.

Treating a non-significant result as proof of no effect

Say whether the confidence interval excludes the effect sizes you would have cared about. If it does not, the honest reading is that the test was underpowered, so report the minimum detectable effect the design could have found and what sample size would resolve it.

Questions & practice

How do you explain the difference between correlation and causation in your models?

Medium · statistics and probability

Approach

  1. Say what the estimate is of, and over what population it generalises.
  2. Translate the result into the decision it informs, in one plain sentence.
  3. Write down the assumption the method needs before you use the method.

Follow-up

  • Which assumption here is most likely to be violated in practice?
  • What sample size would you need to detect an effect half this size?

Explain how you handled data imbalance in a project.

Medium · statistics and probability

Approach

  1. Say what the estimate is of, and over what population it generalises.
  2. Sanity-check the answer against a simple bound or a simulated case.
  3. Translate the result into the decision it informs, in one plain sentence.

Follow-up

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

How do you assess model bias, variance, and overfitting risks?

Medium · machine learning and modelling

Approach

  1. Check what information would not exist at prediction time, and exclude it.
  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

  • 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?

Sessionise search events into trip intents with stable keys

Medium · sessionisation · event streams · hashing · pandas

searches has visitor_id, traveller_id (null while logged out), searched_at_utc, destination_market_id, check_in_date, length_of_stay_nights, party_adults, is_bot_flagged; roughly 5 million rows in arbitrary order. Produce a trip_intent_key grouping searches that represent one trip: same identity, destination_market_id, length_of_stay_nights, party_adults, and check_in_date rounded into a 3-day bucket. Additionally split a group wherever consecutive searches are more than 30 days apart. Return the frame plus trip_intent_key, intent_ordinal, and the searches-per-intent distribution. The key must be reproducible across processes and joinable to a bookings table.

Approach

  1. Drop is_bot_flagged rows before anything else; they are not demand and they distort both the numerator and the searches-per-intent diagnostic.
  2. Build the identity column as traveller_id where present else visitor_id, and say the caveat out loud: most early-funnel searching is logged out, so joining on traveller_id alone discards the majority of the funnel, while the coalesce splits one human's intent in two at the moment they log in.
  3. Bucket the check-in date arithmetically, not by resampling: (check_in_date - pd.Timestamp('1970-01-01')).dt.days // 3. Then sort by [identity, market, bucket, length_of_stay, party_adults, searched_at_utc] and compute the gap with groupby(...)['searched_at_utc'].diff(), flagging gaps over 30 days and taking a cumsum of the flag as a within-group segment number.
  4. Hash the canonical tuple with hashlib (blake2b with a fixed digest_size, hexdigest truncated), not Python's built-in hash(): the built-in is salted by PYTHONHASHSEED per process, so keys differ between runs and the join to the bookings table returns nothing while looking syntactically correct.
  5. Derive intent_ordinal with a groupby cumcount on the sorted frame, and return searches-per-intent as a separate distribution rather than folding it into any conversion rate, since searches per intent is a property of the interface, not of demand.

Worked solution (35 min)

  1. Filter out is_bot_flagged; record the dropped row count as a reported number.
  2. identity = traveller_id.fillna(visitor_id) after casting to a common string dtype; bucket = day-index // 3.
  3. Sort on the full group key plus searched_at_utc; gap_flag = groupby(group_key)['searched_at_utc'].diff() > 30 days; segment = gap_flag.groupby(group_key).cumsum().
  4. Build the canonical string by joining the group key parts and the segment with a separator that cannot occur in any part, and map it through blake2b(digest_size=8).hexdigest() over the unique strings only, then merge back.
  5. intent_ordinal = groupby('trip_intent_key').cumcount() + 1; compute the searches-per-intent distribution with value_counts on the intent sizes.

Expected result: Every retained search maps to exactly one trip_intent_key. No intent spans more than 30 days between consecutive searches. Running the function twice in two separate Python processes produces byte-identical keys. The searches-per-intent distribution is heavily right-skewed: a median of about 3 with a p99 in the tens.

Verify it yourself

  • Two fresh interpreter runs produce identical key sets (this fails immediately if built-in hash() was used)
  • searches.groupby('trip_intent_key')['searched_at_utc'].apply(lambda s: s.diff().max()) never exceeds 30 days
  • Sum of intent sizes equals the non-bot row count; no search is unassigned
  • Shuffling the input rows leaves the key assignment unchanged after re-sorting

Follow-up

  • Two people on one household device search the same city for different dates. What does your key do, and how would you measure how often that happens?
  • How would you defend the 3-day bucket and the 30-day gap empirically rather than by assertion?
  • Look-to-book rose 8% after a release that reduced re-sorting. Has demand conversion improved?

Write a SQL query using advanced functions like LEAD and LAG.

Medium · sql and data manipulation

Approach

  1. State the window function and its partition and ordering out loud before writing it.
  2. Say which table is the grain you start from, and join outward from it.
  3. 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?

How would you optimize a query that is performing poorly on a large dataset?

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. 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

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

Rank market-weeks by qualified intents that never converted

Medium · anti-join · null-semantics · supply-gaps

Using the qualifying-intent definition over fct_search (trip_intent_key, searched_at_utc, destination_market_id, check_in_date, results_returned_count, is_bot_flagged) and fct_booking (trip_intent_key, booked_at_utc), produce a supply-acquisition list: the 20 (destination_market_id, ISO week of check_in_date) pairs with the most qualifying intents that never converted within seven days of their first search. Note that fct_booking.trip_intent_key is NULL for deep-link, offline and partner-channel bookings. Return market, check-in week, non-converting intents and total intents.

Approach

  1. Reuse the qualifying-intent set: non-bot, results_returned_count > 0, collapsed to one row per trip_intent_key carrying its first search timestamp and the check_in_date from that first search.
  2. Write the anti-join as NOT EXISTS, correlated on trip_intent_key with the seven-day window inside the subquery. NOT EXISTS is NULL-safe and lets the planner choose an anti-join.
  3. If you insist on NOT IN, add WHERE trip_intent_key IS NOT NULL to the inner query. Without it, one NULL in the subquery makes the predicate UNKNOWN for every outer row and the result set is empty.
  4. Group by destination_market_id and DATE_TRUNC('week', check_in_date), counting both non-converting and total intents so the reader sees volume and share together.
  5. Order by non-converting intents descending and limit to 20. Ordering by share alone promotes market-weeks with five intents and one miss.

Worked solution (25 min)

  1. Run the inner subquery alone and count its NULLs; that count is the reason the NOT IN form fails and is worth stating out loud before fixing it.
  2. Build the qualifying-intent CTE and record its row count as the control total for the rest of the query.
  3. Write the NOT EXISTS anti-join and confirm that non-converting plus converting equals the control total exactly.
  4. Aggregate to market-week, order by volume, and limit.

Expected result: Twenty rows of (destination_market_id, check_in_week, non_converting_intents, total_intents); the NOT IN variant of the same query returns exactly zero rows, which is the diagnostic worth demonstrating.

Verify it yourself

  • non_converting_intents plus converting_intents equals the total qualifying intents for the same window.
  • No row has non_converting_intents greater than total_intents.
  • Rewriting the anti-join as LEFT JOIN with an IS NULL test gives identical counts; if it does not, the seven-day predicate has drifted into the WHERE clause and turned the LEFT JOIN into an inner join.

Follow-up

  • Which of these market-weeks are a supply shortage and which are a restriction or price problem? Which column separates them, and what join do you need?
  • You run the query and get zero rows. Walk me through how you find out why, without changing the query at random.
  • How would you exclude intents that did convert under a different trip_intent_key, such as the same traveller shifting their dates by a week?

Describe your approach to hypothesis testing and experimental design.

Medium · a/b testing and experimentation

Approach

  1. Decide the analysis before seeing data, including how long it runs and when you look.
  2. Name the guardrails that would stop a launch even on a positive primary result.
  3. Name the randomisation unit first; it decides the variance and what the test can detect.

Follow-up

  • What would you conclude if the result is positive but the test is underpowered?
  • How would you handle interference between treated and control units?

Measure stay quality when only some stays leave reviews

Medium · proxy metrics · selection bias · quality

Ranking and supplier suspension both consume a quality score. The only direct quality signal is fct_booking.review_score on a 1-10 scale, with review_submitted_at_utc, and reviews exist only for bookings reaching booking_status = 'stayed'. NULL means no review, never zero. Roughly a quarter of completed stays are reviewed, and dim_supply_unit.rating_count is near zero for new supply. Define the quality metric a suspension decision can use, state explicitly what the reviewed population is a biased sample of, and say what that bias does to a decision made on it.

Approach

  1. Name the estimand before the estimator: expected stay quality for a randomly chosen future stay at this supply unit. That quantity is not in any table, and review_score is a proxy for it.
  2. Enumerate the selection mechanisms rather than gesturing at bias. Only stayed bookings can review, so cancellations, no-shows and supplier-caused failures are structurally absent from the sample. Response is non-random and skews toward extreme experiences. And rating_count near zero means the estimate for new supply is dominated by noise rather than by quality.
  3. Choose an estimator that fails safe: a mean of review_score shrunk toward the (property_class, destination_market_id) prior with weight rating_count / (rating_count + k), so a unit with three reviews cannot be suspended on them, and publish rating_count and an interval beside the score.
  4. Add signals that do not pass through reviews at all, because they cover exactly the population reviews cannot see: supplier-caused cancellation rate from fct_booking.cancellation_reason = 'supplier', the no_show rate, and servicing_contacts_count per booking.
  5. State the bias direction on the decision itself: a unit whose failures end in a supplier cancellation rather than a bad stay never generates the bad review, so a suspension rule on review score alone systematically spares that failure mode.

Worked solution (30 min)

  1. Compute review response rate by property_class, supplier_type, rate_plan and lead_time_days bucket, and check whether it varies enough to break comparability across those cuts.
  2. Fit the shrinkage constant k by holding out later reviews and comparing the shrunk estimate's error against the raw mean's error at low rating_count.
  3. Build the combined signal: shrunk review mean, supplier-caused cancellation rate, no-show rate and servicing contacts per booking, each with its own window.
  4. Set a minimum rating_count gate below which no suspension can fire on review score alone, and route those units to the non-review signals.
  5. Write the bias paragraph as a deliverable, naming which population is missing and which direction the omission pushes the score.

Expected result: Quality score = review_score mean shrunk toward the (property_class, destination_market_id) prior with weight rating_count / (rating_count + k), published with rating_count and an interval, gated so no suspension fires below a minimum rating_count. Alongside it: supplier-caused cancellation rate, no-show rate and servicing contacts per booking, covering unreviewed and never-completed stays. Bias stated as: the sample is completed, reviewed stays, which excludes the worst outcomes by construction.

Verify it yourself

  • If review response rate varies materially across property_class or rate_plan, the raw mean is not comparable across those cuts and only the shrunk, segmented version is.
  • Suspension candidates selected on review score alone versus on the combined signal should overlap substantially; if the sets barely intersect, the review-only rule is answering a different question from the one asked.
  • NULL review_score rows must never enter the numerator or the denominator as zeros; verify the count of NULLs separately and confirm it matches stays minus reviews.

Follow-up

  • Review response rate rises 8 points after a prompt change. Do historical comparisons of the score still hold?
  • A unit has rating_avg 9.4 on 6 reviews and an 11 percent supplier-caused cancellation rate. What do you do?
  • How would you put a size on the non-response bias without running a survey?

Occupancy spiked in four markets on one snapshot date

Medium · pipeline-failure · denominator · data-quality · geography-cut

Occupancy, computed as stayed nights from fct_stay_night over sellable nights from fct_rate_availability_snapshot (units_sold_to_date + units_available at the latest snapshot_date on or before stay_date), jumped from 71% to 94% in four destination markets for stay dates in a two-week band, and is normal everywhere else. Stayed nights are unchanged. You have fct_rate_availability_snapshot (supply_unit_id, stay_date, snapshot_date, units_available, units_sold_to_date, units_blocked) and dim_supply_unit (listing_status, supplier_id, supplier_type, destination_market_id). Find the cause and state what the true occupancy was.

Approach

  1. The numerator is given as unchanged, so all of the work is in the denominator. Count DISTINCT supply_unit_id per snapshot_date per market and compare it against the count of units with a sellable listing_status in dim_supply_unit. A missing feed shows up as a step down in coverage, not as a change in any per-unit value.
  2. Check row counts per partition. The snapshot table is partitioned on snapshot_date, so a failed load leaves a thin or absent partition and the as-of join quietly falls back to an older snapshot whose units_sold_to_date is lower and whose availability is stale.
  3. Separate the two failure shapes, because they push the rate in opposite directions. Units missing from the snapshot entirely shrink the denominator and inflate occupancy; a stale fallback snapshot understates units_sold_to_date and can deflate it. Naming which one you have determines the correction.
  4. Look for mechanically impossible values rather than merely surprising ones. Occupancy above 1.0 on a stay_date, or a supply_unit_id present in fct_stay_night but absent from the denominator for the same date, is proof rather than suspicion.
  5. Recompute with the denominator restricted to unit-dates that carry a genuine snapshot on the intended date, and publish coverage alongside the corrected rate so the number carries its own caveat instead of needing a footnote.

Follow-up

  • Two of the four markets share a supplier feed and two do not. What does that pattern tell you about where to look next?
  • The pipeline owner wants to backfill the missing partitions. What do you need to see before you republish the corrected series?
  • What single daily check would have caught this before anyone opened the dashboard, and what is its false-positive rate?

Suggested practice checklist

Roughly 90 minutes a night on weekdays with one longer weekend block. The plan deliberately cuts scope rather than compressing everything, on the assumption that finishing one thing a night beats half-starting four.

Day 1 — Fix the scope and set a baseline

  • Read the role description and write the three things the loop will almost certainly test, then write an explicit not-doing list for everything else and keep it visible all week.
  • Take one 20-minute SQL prompt and one 10-minute metric question cold, and write the single sentence that says what blocked each attempt, since that sentence is what decides which two topics get the most evenings.
  • Set the week's one rule: one problem finished to completion every night, including the night you only have 40 minutes.

Deliverable: A one-page scope with an explicit not-doing list and two cold attempts, each carrying one sentence on what blocked it.

Day 2 — One query pattern, written three times

  • Choose the single pattern most likely to appear (a cohort retention grid, or a funnel counted by user) and write it three times from a blank file rather than editing the previous attempt.
  • On the third attempt, write the grain of every CTE as a comment before writing its body.
  • Stop at 90 minutes even if the third version is imperfect, and write the one thing you would fix with another hour.

Deliverable: Three independent versions of the same query plus a note on what changed between them.

Day 3 — Only the statistics you will be asked to defend

  • Write, in under 200 words, how you would decide whether a difference between two groups is real: the test, its assumptions, and what you would switch to when an assumption fails.
  • Compute a 95 percent confidence interval for a difference in proportions by hand on realistic numbers, then write in one sentence what changes if the two samples are paired rather than independent.
  • Write your answer to "what does a p-value mean", check it against a definition, and delete the version that describes it as the probability the hypothesis is true.

Deliverable: A 200-word written answer and one hand-computed interval you can reproduce under pressure.

Day 4 — One case, and the assumptions holding it up

  • Answer one product case aloud in 20 minutes with a recording running, then listen back with a pen and mark every claim you asserted without saying what it rested on: an assumed user behaviour, an assumed data source, an assumed baseline rate, an assumed grain.
  • Pick the three assumptions the recommendation actually depends on, write how you would check each one against data, and say which one being wrong would flip the recommendation rather than merely weaken it.
  • Write the four-step structure you used onto a card small enough to hold in working memory when you are nervous.

Deliverable: One recording, three load-bearing assumptions each with a written check, and a four-step structure card.

Day 5 — Your own work, timed

  • Write a 90-second version and a four-minute version of your main project, and time both out loud rather than reading them.
  • Prepare answers to the two follow-ups that always come: what you would do differently, and how you knew it worked.
  • Put one number in the first sentence and be able to say exactly where that number came from and what it excludes.

Deliverable: Two timed narratives with one defensible number in the opening line.

Day 6 — The one full rehearsal, in a longer weekend block

  • Run a 60-minute mock covering query work, a case and a behavioural question in a single sitting with no breaks, because sustained attention is the thing evenings have not trained.
  • Immediately afterwards, and before hearing any feedback, write the three moments you lost the thread.
  • Spend the rest of the block only on those three moments, and on nothing you merely feel shaky about.

Deliverable: Mock notes naming three failure moments with a specific fix written under each.

Day 7 — Taper

  • Write the 20-minute warm-up you will actually do on the morning of the interview: one query you can already write from a blank file, one metric you can define out loud, and nothing you have never seen before.
  • Re-read only your own notes from this week, and open no new material.
  • Write down the logistics: the tool you will be asked to work in, whether lookups are allowed, and the sentence you will use when you do not know something.

Deliverable: A one-page card holding the case structure, the project numbers, and the logistics.

Ambiguous requests are the test

Most of the questions in this section reduce to one thing: can you be handed a vague request and come back with something useful? Prepare an example where the ask was underspecified, you chose an interpretation, and you said out loud which interpretation you chose. Describing how you narrowed the question matters more than the technique you eventually used.

Describe a time you had to clean a messy or incomplete dataset before modeling.

Medium · behavioural and stakeholder questions

Approach

  1. Quantify the outcome, including what you would not claim credit for.
  2. Close with what you would do differently, concretely.
  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 did you decide not to do, and why?

Describe a time when you were overwhelmed at work. What was the situation, and how did you handle it?

Medium · behavioural and stakeholder questions

Approach

  1. State the situation in two sentences and spend the rest on your reasoning.
  2. Pick a story where you drove the decision, not one where you observed it.
  3. Close with what you would do differently, concretely.

Follow-up

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

Give an executive one number and its honest interval

Medium · communicating uncertainty · forecasting · executive audience

A director must commit contact-centre staffing for a peak stay-week 60 days out. Your pickup forecast from fct_rate_availability_snapshot gives 42,000 stayed nights for that week, with an 80% interval of 36,500 to 47,000. Back-testing shows the interval only narrows materially inside 30 days out. The director has said twice that they want one number and do not want to hear about confidence intervals. You have a five-minute slot and one slide. Prepare what goes on it and what you say.

Approach

  1. Work out the decision before the number: staffing is asymmetric, because under-staffing a peak week costs servicing failures and cancellations while over-staffing costs idle hours. Find out which side is more expensive, because the whole answer is which end of the interval to plan against.
  2. Convert the interval into two staffing levels rather than two stay-night counts. An executive cannot act on 36,500 to 47,000; they can act on 'staff for 44,000 now, with a named trigger to add or release capacity'.
  3. Give the one number they asked for, and attach the trigger to it rather than a caveat: plan at the level implied by the more expensive error, then re-read pickup at 30 days out, which back-testing says is where the interval actually moves.
  4. Say what the uncertainty is made of in one line each, using the domain's own vocabulary: pickup still to come, lead-time mix for that market, and whether the week straddles a moving holiday that shifts against last year.
  5. Close with the decision the interval does not affect, so the director knows the width is not an excuse: if every point in the interval implies the same staffing tier, say so and stop talking about the interval.

Follow-up

  • The week lands 6,000 nights below your point forecast. How do you handle the next forecast conversation with this director?
  • They ask you to just give them the midpoint and skip the trigger. What do you do?
  • How would you decide whether an 80% interval is the right one to show rather than a 50% or a 95%?