cswork / libraryOpen practice workspace

Interview guides · ATG Entertainment

ATG Entertainment Data Scientist Interview Questions & Guide 2026

Case practice for ATG Entertainment data scientist candidates: scope a vague prompt into a measurable question before you analyze it.

The 60-second brief

As a Data Scientist at ATG Entertainment, you sit at the intersection of world-class live entertainment and data-driven personalization. Your work directly influences how millions of audience members engage with iconic venues, from historic theatres to modern music arenas. By building and refining machine learning models, you help bridge the gap between artistic performance and customer experience, ensuring that every interaction—from initial marketing contact to the final curtain call—is tailored and impactful.

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

  • Measure catalogue breadth beyond head consumption
  • Correct discovery slates for position bias
  • Separate release-calendar spikes from underlying trend

Overview

This role is both highly technical and deeply collaborative. You will not be working in a silo; instead, you will partner closely with CRM and Marketing teams to turn complex datasets into actionable insights that drive conversion and engagement. Whether you are developing propensity models, optimizing segmentation, or designing robust measurement frameworks, your contribution is fundamental to the ATG Entertainment mission of creating a "stage for everyone." You will be expected to own your models from conception to testing, while collaborating with ML Engineers to bring your solutions to production.

Given the global nature of ATG Entertainment, emphasize your ability to work cross-functionally across US and UK teams during your interviews.

The ATG Entertainment interview process

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

Initial Discussion

An added round often puts you in front of someone outside the core hiring team: a partner engineer, a product owner, a domain expert, sometimes a more senior manager. The question they are really asking is not whether you can do the work but whether they would trust a number that came from you. That changes what a good answer looks like. Lead with what the decision cost and what it changed, keep the method available but not central, and be plain about the limits of your evidence. Overstating a result is the fastest way to lose this round.

What to demonstrate

  • Whether you can explain a technical choice to someone who will never read your code, without either flattening it into nothing or hiding inside jargon
  • Honesty about evidence strength: what the analysis establishes, what it only suggests, and what it cannot say at all
  • How you take disagreement, specifically whether you update on a good objection, hold your position with reasons, or fold on contact

How to prepare

  • Write the two-sentence version of your most technical project for a non-specialist, then check that neither sentence needs a method name to make sense.
  • For one result you are proud of, write the strongest objection someone could raise and a response that concedes the part of it that is correct.
  • Prepare one decision that turned out to be wrong: how you found out, what it cost, and what you changed afterwards. A senior cross-functional interviewer asks for this more often than a technical one does.

Intensive Assessment

Before anything else, this round is a reading test. You are given a small schema and a question phrased in business language, and most of the difficulty sits in the gap between them. Who counts as an active user, does a refunded order still count as an order, is that date column an event time or a load time. Weak answers start typing immediately and compute something precise about the wrong population. Strong ones pin the definition in one sentence, name the column that encodes it, then write the query. On a timed assessment with nobody to tell, write the definition in a comment anyway.

What to demonstrate

  • Whether an ambiguous term becomes a specific column and filter before any computation happens
  • Whether you read the schema for keys and cardinality rather than only for column names
  • Whether the result answers the question at the grain it was asked at, per user or per session or per day

How to prepare

  • Take three metrics you already use and write down the exact filter and exact grain behind each, then practise stating one of them in a single sentence out loud
  • On a schema you have never seen, spend the first minute writing what one row of each table means and which key it is unique on, then predict which joins can duplicate rows
  • Rehearse a version where the definition changes halfway through, and edit the query you have instead of starting over

Presentation

Because the format is not fixed, prepare the reasoning rather than the ritual. Nearly every version of this round draws on the same underlying material: a design you can defend, a metric you can define exactly, an analysis whose assumptions you can state out loud. Only the wrapper changes, whether that is a take-home, a live case, a deep dive on past work, or a rough estimate on a whiteboard. Answers rehearsed to fit one shape stall the moment the shape differs. Practise naming the assumption behind a number, then saying how much the conclusion moves if that assumption is wrong.

What to demonstrate

  • Whether your justification for a method survives the question 'why not the simpler thing', including when the simpler thing would have worked
  • Precision under pressure: what exactly counts as an active user, a conversion or a success, over what window, with what exclusions
  • Whether you carry an argument through to a recommendation instead of stopping at a list of tradeoffs

How to prepare

  • For each project you plan to mention, write the metric definition in one sentence: numerator, denominator, time window, exclusions. Say it out loud once, because vagueness shows up in speech before it shows up on paper.
  • Rehearse the same project at three lengths: two minutes, ten minutes, and a deep dive on one technical decision. Cutting live is harder than it sounds.
  • For your headline result, write down what would have had to be true for it to be wrong, and how you ruled that out.

Where candidates lose points

Treating the account as the person, or the profile as the person.

A household account carries several people, profiles frequently are not switched, and shared-screen, car and speaker playback often lands on a default profile with no user behind it. Personalisation trained on a profile therefore learns a mixture, retention regressions attribute one member's behaviour to another, and a per-account taste statistic describes a household composite. The practical consequence is that apparent personalisation wins can be device or context effects, so any identity-level claim needs a stated unit and an acknowledgement of what that unit actually aggregates.

Counting plays without a qualification threshold, or changing the threshold without restating history.

Playback arrives as heartbeats, so a play only exists once you decide what counts, and the common 30-second convention is not a neutral analytics choice: in music it is also the boundary at which a play becomes payable, which makes the warehouse definition a payout definition. The threshold interacts violently with content length, so a catalogue of three-minute tracks and one of forty-minute episodes move in opposite directions when you change it, and a skip-heavy surface can add plays while adding no hours. Any metric mixing pre-threshold and post-threshold counts, or pooling short-form and long-form on a per-stream basis, moves by double digits for reasons that have nothing to do with the product.

Answering a product-sense question with a list of features

Answer with a decision and the measurement that would settle it: the hypothesis, the primary metric, the guardrails, and the result that would make you not ship. A feature brainstorm cannot be wrong, which is exactly why it earns no points.

Comparing periods without accounting for seasonality or day-of-week

Compare whole weeks against whole weeks and check whether the same swing appeared in prior cycles or prior years before attributing it to anything you changed. Weekday and weekend populations often differ enough that a Tuesday-to-Saturday comparison is meaningless.

Questions & practice

Describe your process for validating a model before it goes into production.

Medium · machine learning and modelling

Approach

  1. Pick an evaluation metric that matches the cost of each error type, not a default.
  2. Check what information would not exist at prediction time, and exclude it.
  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?
  • Where could label leakage enter this setup?

How would you approach building a propensity model for ticket sales?

Medium · machine learning and modelling

Approach

  1. Set a baseline first, so any model has something honest to beat.
  2. Frame the prediction: the label, the moment of prediction, and the action it triggers.
  3. Check what information would not exist at prediction time, and exclude it.

Follow-up

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

Explain the trade-offs between different machine learning algorithms for customer segmentation.

Medium · machine learning and modelling

Approach

  1. Say how the offline result would be validated online before it is trusted.
  2. Check what information would not exist at prediction time, and exclude it.
  3. Set a baseline first, so any model has something honest to beat.

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?

Simulate concurrent-stream refusals on a shared family account

Medium · simulation · probability · queueing

A family account has four profiles and max_concurrent_streams = 2. Across an evening window of six hours, each profile independently attempts playback as a Poisson process at 0.75 attempts per hour. Durations are lognormal with a median of 24 minutes and sigma 0.6 on the log scale. An attempt arriving while two streams are already active is refused and abandoned, not retried or queued. Estimate the share of attempts refused and the mean refusals per account-evening, each with a 95 percent interval, then repeat with the cap at three.

Approach

  1. Simulate event-driven rather than on a time grid: draw exponential inter-arrivals per profile at rate 0.75 per hour, pool and sort the arrival times, and carry a short list of active end times.
  2. At each arrival, discard end times at or before that instant, then refuse if two remain. Only a served attempt draws a duration and pushes arrival plus duration; drawing a duration for a refused attempt and letting it hold a slot models a queue instead of a refusal.
  3. Start the window empty and do not warm it up, because the question is about an evening that begins with nobody streaming. Say explicitly that this makes the simulated share read below the steady-state value.
  4. Size the replications from a pilot: run 2,000 evenings, read the observed share, then solve 1.96 times the standard error to at most 0.002 using the between-evening standard deviation of the per-evening refusal share.
  5. Re-run with the cap at three by changing one constant and report the pair, because the decision this feeds is whether the cap is what the refusals are about.

Worked solution (30 min)

  1. Write one evening as a function: per profile, cumulative exponential draws with scale 1/0.75 hours truncated at 6 hours, then concatenate and sort the arrival times.
  2. Sweep arrivals in order against a list of active end times: pop the expired, refuse if the list is already at the cap, otherwise draw a lognormal duration with mean parameter log(24/60) and sigma 0.6 in hours and append arrival plus duration.
  3. Return (attempts, refusals) per evening; run a 2,000-evening pilot, take the per-evening refusal share, and size the full run from its standard deviation.
  4. Run the sized number of evenings at cap 2 and again at cap 3, with a fixed seed per configuration.
  5. Report the pooled share (total refusals over total attempts) with a clustered interval built from the per-evening shares, plus the mean and 90th percentile of refusals per evening.

Expected result: At cap 2, a refused share of roughly 0.25 to 0.30 and about four to five refusals per evening; at cap 3, roughly 0.10 to 0.13. Both sit just below the Erlang-B steady-state values for an offered load near 1.44 erlangs, which are 0.297 and 0.125.

Verify it yourself

  • Erlang-B at a = 1.44 gives B(2) = (a squared over 2) divided by (1 + a + a squared over 2) = 0.297, and B(3) = 0.125. Lengthening the window from 6 to 48 hours should pull the simulation up toward these.
  • Raising the cap to a large number drives refusals to exactly zero; setting it to zero refuses every attempt. Both are cheap wiring checks.
  • Mean attempts per evening is 4 times 0.75 times 6, which is 18 within Monte Carlo error. Confirm the arrival process before trusting any refusal logic.
  • The sampled mean duration is 24 times exp(0.6 squared over 2) = 28.7 minutes, not 24. A sampled mean of 24 means the lognormal was parameterised on the mean instead of the median.

Follow-up

  • What changes if a refused attempt retries after two minutes instead of being abandoned?
  • Erlang-B gives a closed form for this. Where does it agree with your simulation and where does it not?
  • How would you find these refusals in fct_stream, given that a refused attempt produces no stream row at all?

Pick one canonical version per work without losing remaster plays

Medium · deduplication · window functions · dimension grain

dim_content_version has content_version_id, content_id (stable across versions of the same work), title, content_type, duration_seconds, catalogue_added_ts, is_active_version and updated_at. A remaster, re-edit, dub or re-encode is a new row sharing content_id, and more than one row per content_id can carry is_active_version = true. Produce exactly one canonical row per content_id, preferring is_active_version = true, then the latest catalogue_added_ts, then the highest content_version_id as a deterministic tie-break. Then join fct_stream (content_version_id, played_seconds, is_qualified, started_at) and report qualified hours per content_id for last month.

Approach

  1. ROW_NUMBER() OVER (PARTITION BY content_id ORDER BY is_active_version DESC, catalogue_added_ts DESC NULLS LAST, content_version_id DESC), keeping rn = 1. The third sort key exists only so two runs return the same row; without it the winner among ties is whatever the engine happened to produce, and the result diffs against yesterday for no reason.
  2. Spell NULLS LAST out. In PostgreSQL, DESC defaults to NULLS FIRST, so a version with no catalogue_added_ts would win the canonical slot ahead of every dated one. Other engines order NULLs differently, which is exactly why the clause belongs in the query rather than in your head.
  3. Aggregate the streams first, at content_id grain, by joining fct_stream to dim_content_version on content_version_id and grouping on content_id. Every version's plays belong to the work.
  4. Only then attach the canonical attributes, with a join from the aggregate to the rn = 1 CTE on content_id. Inner-joining fct_stream to the canonical row instead discards every play of every non-canonical version, which is most of the catalogue's remasters and all of its dubs.
  5. Report the count of content_ids carrying more than one is_active_version row as a data-quality line beside the result, since that condition is what made the dedup necessary and its size decides whether this is a query fix or a pipeline fix.

Follow-up

  • Which grain should hours be reported at, content_id or content_version_id, and who is the consumer of each?
  • Rights expire per version, so one version's window can be closed while another is live. What does your canonical pick then mean for an availability report built on the same CTE?

Daily qualified hours on local dates with trailing seven-day sums

Hard · timezones · window functions · running aggregates · late-arriving data

fct_stream has account_id, started_at (UTC), event_date (date partition key derived from started_at), played_seconds, is_qualified and play_territory (ISO-3166-1 alpha-2, resolved at play time). A lookup tz_offset(territory, utc_offset_minutes) gives each territory a fixed offset. Product wants daily qualified hours for March 2026 on each territory's local calendar date, not UTC, plus a trailing seven-day sum per territory. Offline plays upload days late with started_at backdated. Return territory, local_date, qualified_hours and trailing_7d, and state which of event_date and started_at you filter on and why.

Approach

  1. Derive local_date = (started_at + utc_offset_minutes * INTERVAL '1 minute')::date, joining the lookup on play_territory rather than the account's signup_country. A play belongs to the clock where it happened; signup_country is a property of the account's origin and is wrong for anyone who travels or who signed up under a bundle sold in another market. Say out loud which one the requester meant.
  2. Scan wide, then narrow. To cover local March everywhere you must read UTC 2026-02-28 through 2026-04-01, because a territory at UTC+13 begins its 1 March at 11:00 UTC on 28 February, and one at UTC-11 is still in 31 March at 10:00 UTC on 1 April. Put the widened range on event_date so the partition prune still happens, then filter local_date to March in the outer query.
  3. State the precondition on the offset. A single fixed offset per territory is only correct while no daylight-saving transition falls in the window, and several territories shift during March. Either resolve with a real zone (started_at AT TIME ZONE an IANA name) or accept a bounded error: at most one hour of plays per affected territory moves across one date boundary, on one day of the month.
  4. Aggregate to (territory, local_date), then take the trailing window. Prefer SUM(...) OVER (PARTITION BY territory ORDER BY local_date RANGE BETWEEN INTERVAL '6 days' PRECEDING AND CURRENT ROW), which is calendar-correct even when a territory has a day with no qualified streams. ROWS BETWEEN 6 PRECEDING is correct only on a dense date spine — on a gapped series it silently reaches back more than seven calendar days.
  5. Say what the number means for the recent edge. event_date follows the backdated started_at, so a late offline upload lands in a day you already published and that day's figure grows after the fact. Either restate closed days on every run and publish a revision, or carry an ingestion-time column and report the figure as-of a stated load.

Worked solution (45 min)

  1. Build a dense (territory, local_date) spine covering 2026-02-23 through 2026-03-31, so every March row has six full preceding days available to its window.
  2. Compute local_date over a UTC scan widened to event_date BETWEEN '2026-02-28' AND '2026-04-01' (widened further for the spine's February tail) and aggregate SUM(played_seconds)/3600 where is_qualified.
  3. LEFT JOIN the aggregate onto the spine, COALESCE hours to 0, apply the RANGE window, then restrict output to local_date in March.
  4. Re-run the identical query a week later and diff the early-March days to measure how much the late offline uploads moved a closed number.

Expected result: 31 rows per territory covering local_date 2026-03-01 through 2026-03-31, with qualified_hours >= 0 and trailing_7d equal to the sum of that row and the six preceding spine rows — full windows throughout, because the spine starts in February.

Verify it yourself

  • For a territory at UTC+00 the local-date total and the UTC event_date total for March are identical; for every other territory they differ by exactly the boundary hours, which is the evidence the conversion did something.
  • trailing_7d on any row equals the manual sum of qualified_hours over that row and the six preceding spine rows, including rows that are zero.
  • Dropping the spine's February tail changes trailing_7d for the first six March days and nothing else, confirming the frame is reaching back seven calendar days rather than seven present rows.

Follow-up

  • A territory changes its UTC offset mid-month. What happens to your March total, and what do you print for the local day that is 23 or 25 hours long?
  • Would you key on play_territory or the account's signup_country? Give a concrete case where they differ and the choice changes the answer.
  • What do you publish for the most recent day while offline uploads are still arriving, and how do you communicate that it will move?

What metrics would you prioritize when evaluating a recommendation system?

Medium · product sense and metrics

Approach

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

Follow-up

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

How would you measure the success of a new personalized email campaign?

Medium · product sense and metrics

Approach

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

Follow-up

  • Which segment would you cut first, and what would that rule out?
  • What would you do if the primary metric and the guardrail moved in opposite directions?

If a marketing campaign underperforms, what steps do you take to diagnose the issue?

Medium

Approach

  1. State your assumptions explicitly before working the problem.
  2. Say what you would check first and why it is the highest-information step.
  3. 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?

Trade retention against revenue on an ad-supported tier

Medium · metric design · guardrail conflict · advertising · lagged effects

The free_ad_supported tier proposes raising ad breaks per delivered hour. The company metric is net revenue per active account-month; the stated guardrails are advertising seconds per delivered content hour and trailing 90-day retention of ad-supported accounts. Using fct_stream (account_id, ad_breaks_served, ad_seconds_played, played_seconds, is_qualified) and fct_subscription_period (account_id, net_amount_usd, period_end_ts, renewal_outcome), design the decision: primary metric, guardrails, and an explicit exchange rate saying how much retention you would spend for a revenue point. A four-week test is all you are offered.

Approach

  1. Say plainly that this is a real conflict, not a monitoring exercise: raising ad load moves the primary metric up and the guardrail down through the same mechanism, so no definition of either metric makes both improve and the job is to price the trade, not to find a metric that hides it.
  2. Decompose the primary so the conflict is visible in the algebra: net revenue per active account-month equals ad seconds per delivered content hour times delivered content hours per active account-month times net revenue per ad second, and the change raises the first term while lowering the second, with the third term falling too if added inventory clears at a lower price.
  3. Establish that a four-week test cannot read the guardrail: the retention response is lagged past the window, so the test is powered on the numerator and will return a significant revenue gain against a retention estimate whose confidence interval spans the effect sizes that would kill the launch. State the required holdout instead, held at least 90 days at a size chosen to detect the retention drop that would break even.
  4. Convert both sides into one currency before arguing: expected lifetime value per ad-supported account equals net revenue per active account-month times expected retained months, so a 1 percent revenue gain is worth taking only if the retention cost is under roughly 1 percent of expected retained months, and write that break-even as the exchange rate.
  5. Keep one guardrail non-tradeable: advertising seconds per delivered content hour gets a hard ceiling that no revenue gain buys past, because an exchange rate alone permits an unbounded walk up the ad-load curve one defensible step at a time.
  6. If the four weeks must produce a decision, name the surrogate explicitly and its bias: weeks three and four qualified hours per account-week among treated accounts, which understates the retention harm because the accounts most likely to leave are still present and still consuming during the window.

Worked solution (35 min)

  1. Write the decomposition of net revenue per active account-month into ad seconds per content hour, content hours per account-month and revenue per ad second, and mark the sign of the ad-load change on each term.
  2. Write the lifetime-value identity for an ad-supported account and differentiate it into the break-even condition: the launch is positive only when the proportional revenue gain exceeds the proportional loss in expected retained months.
  3. Plug in one concrete pair: a 3 percent revenue-per-account-month gain breaks even against roughly a 3 percent fall in expected retained months, which on a 14-month expected tenure is about 0.4 months, and translate that into the 90-day retention drop it corresponds to.
  4. Specify the measurement plan: four-week test reads the revenue term and the ad-seconds guardrail only; a separately sized holdout of ad-supported accounts is held 90 days and is the only thing allowed to move the retention number.
  5. Write the ship rule with the hard ceiling first, then the exchange rate, then the holdout condition, and state which of the three is not negotiable.

Expected result: Primary: net revenue per active account-month. Guardrails: advertising seconds per delivered content hour with a hard non-tradeable ceiling, and trailing 90-day retention of ad-supported accounts read from a dedicated holdout, not the four-week test. Exchange rate stated as a break-even: the proportional revenue gain must exceed the proportional loss in expected retained months, with the worked figure around 3 percent against roughly 0.4 months on a 14-month tenure. The candidate must say the conflict is genuine.

Verify it yourself

  • The decomposition has ad load raising one term and lowering at least one other, which is the formal statement that the conflict cannot be defined away.
  • The break-even is expressed as a comparison of two proportional changes, so it does not depend on getting the absolute lifetime value right.
  • The four-week test is explicitly not permitted to clear the retention guardrail, and the reason given is power and lag rather than a preference.
  • The ad-seconds ceiling is stated as a bound rather than a term in the exchange rate, which is what stops an incremental walk up the curve.

Follow-up

  • Net revenue per ad second falls as load rises because added inventory clears cheaper. How does that change your break-even, and does it make the decision easier or harder?
  • How large must the 90-day holdout be to detect a one-percentage-point retention drop, and what does that cost in forgone revenue while it runs?
  • The four-week result is a 3 percent revenue gain with a retention estimate of minus 0.4 points plus or minus 1.5. What do you recommend, in one sentence, and what do you refuse to claim?

Qualified streams drop the week a client shipped

Easy · instrumentation · release-debugging · segmentation

Qualified streams in fct_stream (is_qualified, played_seconds, max_position_seconds, app_version, device_type, started_at, ended_at, end_reason) fell 11% on phone in the seven days after version 8.4.0 reached staged rollout. Smart TV and desktop are flat. The mobile team says nothing in the release touched playback. Using fct_stream and dim_profile only, decide within one day whether engagement fell or whether the client stopped reporting playback correctly, and say what evidence settles it. Deliverable: a one-page finding with the decomposition and a recommendation on whether to halt the rollout.

Approach

  1. Split the 11% into stream count and per-stream played_seconds. Cut phone streams by app_version into 8.3.x and 8.4.0 on the same dates and compare starts per active profile-day against played_seconds per start. A real engagement fall moves starts; a telemetry fall moves played_seconds per start while starts hold.
  2. Check the accrual mechanics that change silently: share of rows with ended_at null, share with end_reason in ('unknown','app_kill'), and the played_seconds distribution in 5-second buckets from 0 to 60. A heartbeat regression piles rows up just under 30 seconds and raises the null-ended_at share, because is_qualified is a threshold on a counter rather than on the fact of playback.
  3. Use the staged rollout as the control, but use it correctly. Within phone and within the same dates, prefer profiles that have streams on both versions so each profile is its own before-and-after. Rollout order is not random — early upgraders skew toward frequent users — so report the within-profile change and treat the between-version gap as an upper bound.
  4. Compare max_position_seconds per start against played_seconds per start. max_position_seconds is the furthest playhead reached and does not depend on how time is accrued, so if the playhead still travels the same distance while played_seconds falls, playback happened and the counter is wrong. That comparison is decisive; the others are only suggestive.
  5. Recommend on the basis of which number moved. Halt the rollout for an engagement regression only if starts fell. If accrual broke, the halt is a data-integrity call, the affected days need a caveat on every series built on played_seconds, and the music payout path that reads is_qualified has to be told the same day.

Follow-up

  • If played_seconds under-reports on 8.4.0, how would you restate the qualified-stream series across the rollout window rather than blanking it?
  • Staged rollout is ordered by store and device, not randomised. What does that do to a between-version estimate, and how would you bound the bias?
  • The per-stream payout boundary is the same 30-second threshold. Who needs to know, and before what deadline?

Suggested practice checklist

Instead of guessing where the week should go, day one measures it under a fixed rubric and allocates the remaining hours in proportion to the gaps. The method is deliberately rigid: the allocation is written down before any studying starts and is not renegotiated when a topic turns out to be unpleasant.

Day 1 — Diagnostic, scored before you study anything

  • Sit a 100-minute timed diagnostic in four blocks: 30 minutes of SQL across three prompts, 25 minutes of short-answer statistics, 25 minutes on one modelling or case prompt, and 20 minutes delivering one behavioural story aloud.
  • Score each block from 0 to 3 on a fixed rubric where 3 is correct and fluent, 2 is correct but slow or prompted, 1 is partially correct, and 0 is stuck, grading the output rather than how the attempt felt.
  • Allocate the hours for days two to five roughly in proportion to 3 minus the score in each block, write the allocation down, and commit to not revising it midweek.

Deliverable: A scored rubric and a fixed hour allocation for the rest of the week.

Day 2 — Largest gap: find the boundary rather than the subject

  • Break the weakest area into five named sub-skills (for query work: grain control, window frames, date arithmetic, set logic with NULLs, and reading a query plan) and rate each one, so the rest of the week targets a sub-skill instead of a subject.
  • Solve three problems chosen to sit just above where the rating drops off, and for each write the first move you failed to make.
  • Re-solve one of them from memory four hours later, on paper, with nothing open.

Deliverable: A five-item sub-skill map with the two blocking sub-skills circled.

Day 3 — Largest gap: drill the blocking sub-skill

  • Do eight short repetitions of the same shape rather than eight different problems, so what you practise is the pattern and not the puzzle.
  • Write the rule you now hold in one sentence, then test it against a case built to break it: a ranking function over a column with ties, or a two-sample test on observations that are obviously dependent.
  • Have someone else read your one-sentence rule and find the precondition you left out.

Deliverable: One rule statement with its preconditions attached and one counterexample that would have caught the incomplete version.

Day 4 — Second gap, plus maintenance on your strongest area

  • Run the same sub-skill map and boundary protocol on the second-largest gap, compressed into half the day.
  • Spend 25 timed minutes on your strongest area to stop it decaying, choosing the hardest problem you can still finish rather than an easy warm-up.
  • Compare how the two areas fail: whether you lose time on recall, on setup, or on arithmetic, because the fix differs for each.

Deliverable: A second sub-skill map plus a one-line diagnosis of how each area fails you.

Day 5 — The gap that is not a skill

  • Record yourself answering one technical and one behavioural prompt, then count two things in the playback: how many seconds before your first clarifying question, and how many sentences you started without knowing where they ended.
  • Rewrite your three most-used stock phrases into shorter versions, and practise saying "I do not know, here is how I would find out" without softening it into a guess.
  • Deliver one answer again with a hard 90-second limit to force structure before detail.

Deliverable: Two recordings with a counted improvement in time-to-first-question.

Day 6 — Retest under day-one conditions

  • Sit the same 100-minute diagnostic structure with new prompts of comparable difficulty and score it on the identical rubric.
  • Compare block by block, and for any block that did not move, change the method rather than adding hours: a block stuck at 1 usually means the practice was too varied, not too short.
  • Write which single block you would still lose the offer on.

Deliverable: A second scored rubric placed next to the first, with one named remaining risk.

Day 7 — Full loop under interview conditions

  • Run a 60-minute mock covering the two blocks that moved least, with an interviewer instructed to interrupt and change direction.
  • Write your recovery script for the moment you go blank: restate the question, state your assumption, name the first thing you would check.
  • Reduce the week to the rule statements you wrote, each with its preconditions attached, then say every one of them out loud without reading it and cut any you cannot state in a single sentence, since a rule you have to reconstruct mid-answer will not survive being interrupted.

Deliverable: A one-page card holding the recovery script and only the rules you could state from memory.

What the behavioural round is actually scoring

Interviewers here are not checking whether you can describe a project. They want the decision you made, why you made it under the information you had, and what changed afterwards that someone else could measure. A story that ends at 'I built a model' has no ending. Say what the model caused, or what you stopped doing because of it.

How do you handle imbalanced datasets in a marketing or CRM context?

Medium · behavioural and stakeholder questions

Approach

  1. Quantify the outcome, including what you would not claim credit for.
  2. Name the disagreement or constraint, and how you resolved it with evidence.
  3. Close with what you would do differently, concretely.

Follow-up

  • What did you decide not to do, and why?
  • How did you know the outcome was caused by your change?

Describe a time you had to pivot your technical approach based on business feedback.

Medium · behavioural and stakeholder questions

Approach

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

Follow-up

  • What did you decide not to do, and why?
  • How did you know the outcome was caused by your change?

Arbitrate three requests for the same analyst week

Easy · prioritisation · stakeholder management · scoping

Three requests land on the same Monday for the same week of your time. Growth wants trial-to-paid conversion recut by signup_channel before a budget meeting on Thursday. The playback team wants rebuffer ratio cut by cdn_pop, device_type and network_type after a bitrate ladder change went out Friday. Catalogue wants a displacement estimate for a title that arrived on a rights window last month. You have roughly four working days. Deliverable: your ordering with the criterion behind it, what you tell the two people who do not get the week, and one thing you ship to all three by Tuesday.

Approach

  1. The probe is your criterion, not your ordering. Rank by how reversible the pending decision is and how fast the evidence decays, and say so; ranking by requester seniority is the default answer and reads as one.
  2. Put the playback request first on those grounds: a bitrate ladder change is live and degrading real playback now, and rebuffer ratio is defined on a trailing 24 hours, so the evidence is perishable and the query is small. Cheap and perishable beats expensive and durable.
  3. Ask each requester what they do differently at each plausible answer. The trial-to-paid recut is a defined tree metric — trailing 28 days, read at trial length plus 21 days so dunning retries have resolved — so it is largely a filter plus an hour confirming that unattributed stays its own line rather than being reallocated pro rata.
  4. Treat the displacement estimate as the only genuinely new analysis and scope it rather than squeezing it: it needs a matched comparison group and a pre-registered window, because consumption of the rest of the catalogue moves on the release calendar regardless. Defer it with a date and a stated shape, never silently.
  5. Reply to all three in one thread with the ordering and the criterion visible, so a stakeholder who disagrees argues with the criterion instead of escalating about their position in the queue.

Follow-up

  • The catalogue lead escalates to your manager on Tuesday. Walk me through that conversation.
  • How does the ordering change if the bitrate ladder change was already rolled back on Saturday?
  • All three deadlines are genuine and none can move. What do you actually cut?