cswork / libraryOpen practice workspace

Interview guides · Gramener

Gramener Data Scientist Interview Questions & Guide 2026

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

The 60-second brief

The Data Scientist role at Gramener is integral to transforming complex data into actionable insights, directly impacting decision-making processes and business strategies. As a Data Scientist, you will leverage advanced analytics, machine learning algorithms, and data visualization techniques to derive insights that drive innovation and efficiency across various domains. Your work will not only enhance the user experience but also contribute to the overall growth and success of the organization.

The boundary with engineering varies enough to be worth asking about directly. Some seats end at the analysis and the writeup; others carry feature pipelines, scheduling and alerting, which decides whether production data plumbing belongs in your prep at all.

Focus areas

  • Measure catalogue breadth beyond head consumption
  • Correct discovery slates for position bias
  • Define a qualified stream and defend it

Overview

In this role, you will engage with cross-functional teams to tackle challenging problems, such as optimizing customer engagement through predictive analytics or improving operational efficiency via data-driven solutions. The complexity and scale of the problems you'll address make this position both exciting and crucial. You will be at the forefront of product development, influencing how teams approach data challenges and deliver value to users.

The Gramener interview process

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

Preliminary Screening

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.

Technical Assessments

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

HR Round

This round decides whether you owned a decision or watched one happen nearby. Interviewers for data roles listen for the point where the analysis stopped being a report and started changing what someone did, so build each story around that hinge: what was going to happen by default, what you found, and what happened instead. The most common weakness is a story that ends at delivery. If you can name the decision your work changed and the number that moved because of it, most follow-ups become easy.

What to demonstrate

  • Whether the decision was yours to influence, or whether you are narrating a team outcome in the first person
  • The counterfactual: what would have been done without your analysis, and why that default was worse
  • How far your involvement ran past the handoff, and whether you checked that the change did what you predicted

How to prepare

  • Pick three projects and write one sentence for each naming the decision-maker, the choice in front of them, and what they chose after seeing your work. If you cannot name a person and a choice, the story is not ready for this round.
  • Reconstruct the baseline for your strongest project from the original query or dashboard rather than memory, so the before-number survives a follow-up asking where it came from.
  • Prepare an honest version of a project where your recommendation was overruled, including what you did with the analysis afterwards.

Where candidates lose points

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.

Comparing consumption week over week across the release calendar and the rights calendar.

A major release, a season drop or a live event produces a spike that dwarfs almost any treatment effect, and the effect is not confined to the new title because it pulls attention from everything else in the same window. Separately, licensed content leaves the catalogue when its window expires, so consumption falls with no product change and the drop is attributed to whatever shipped that week. Both need to be handled by an explicit control: a comparison period chosen for calendar equivalence, a covariate for scheduled releases, or a pre-registered rule for excluding a window, decided before the numbers are seen.

Solving silently instead of narrating the reasoning

Say which branch you are taking and why you chose it over the alternative, for example checking the denominator first because it changes what the comparison means. A correct answer that arrives with no visible path scores below a rigorous one that needed a hint.

Reading experiment results before checking the arm split

Compare observed arm counts against the intended allocation ratio, not an assumed even split, and set the alarm far below the conventional 0.05: at 0.05 roughly one healthy experiment in twenty trips it, which is why sample-ratio checks usually run at p < 0.001 or stricter. The test's power scales with sample size, so it misses a real diversion on a small experiment and fires on an imbalance too small to move the estimate on a very large one. A flag means go find the assignment or logging fault before reading any outcome, not report a mismatch.

Questions & practice

Discuss how you would scale a machine learning model for production use.

Medium · machine learning and modelling

Approach

  1. Pick an evaluation metric that matches the cost of each error type, not a default.
  2. Set a baseline first, so any model has something honest to beat.
  3. Say how the offline result would be validated online before it is trusted.

Follow-up

  • What would you monitor after launch to know the model is still valid?
  • Where could label leakage enter this setup?

Permutation test for hours per account across two ranker arms

Medium · permutation-test · heavy-tails · experiment-analysis

arm_hours holds one row per account: account_id, arm in {control, treatment}, qualified_hours over a seven-day window. Roughly 40 thousand accounts per arm, about 38 percent of them at zero hours, and the non-zero tail is long. Without calling a library test function, write a permutation test on the difference in mean hours with 10,000 relabellings. Then run it as two parts: the difference in the share of accounts with any hours, and the difference in mean hours among accounts with hours. Report all three and say which belongs in the readout.

Approach

  1. Shuffle the labels, not the data. Draw a permutation of the arm indicator over accounts, which is the unit that was randomised, and hold the hours vector fixed.
  2. Make each replication O(n): precompute the grand sum and the arm sizes, so a shuffled difference is the treated subset sum over n_t minus (grand sum minus that subset sum) over n_c. Ten thousand replications then take seconds instead of a minute.
  3. Use the two-sided p-value (1 + count of permuted absolute differences at or above the observed) divided by (B + 1). The plus one is not cosmetic: it makes the p-value valid rather than optimistic, and it means the smallest reportable value here is 1/10001, not zero.
  4. For the two-part version, run the same machinery on the 0/1 indicator for the rate, then on the non-zero subset for the conditional mean, and say plainly that conditioning on a post-treatment outcome breaks the randomisation, so the conditional arm is descriptive rather than causal.
  5. Report the rate test and the overall mean test as the result, with the conditional mean as colour, and give the effect size in hours beside each p-value, because at 80 thousand accounts almost anything is detectable.

Follow-up

  • The permutation p-value on the mean is 0.03 and the rate test is flat. What is the most likely explanation, and does it change the decision?
  • How would CUPED on pre-period hours change your power here, and what would disqualify a covariate?
  • Accounts are households. Does that affect the validity of this test, or only its interpretation?

Qualified hours per active account-week from its written definition

Easy · pandas · metric-definition · aggregation

You are given fct_stream as a pandas frame (stream_id, account_id, started_at in UTC, played_seconds, is_qualified) and dim_account (account_id, is_test_account), plus an as-of timestamp. Implement this metric exactly: the numerator is sum(played_seconds)/3600 over qualified streams started inside the window; the denominator is the count of distinct (account_id, ISO week) pairs with at least one qualified stream in that week; the window is the four most recent ISO weeks that are complete as of the given timestamp. Exclude test accounts. Return the scalar and the four per-week rows.

Approach

  1. Drop test accounts first, then filter to is_qualified. The denominator is defined on qualified streams, so filtering after grouping quietly lets an account-week in on the strength of an unqualified stream.
  2. Derive the ISO key with started_at.dt.isocalendar() and keep BOTH iso_year and iso_week. The week number alone collides every January and silently merges two different years of a week into one cell.
  3. Fix the window from the as-of timestamp rather than from max(started_at): a week is complete only when its Monday 00:00 UTC plus seven days is at or before the as-of instant, which is what excludes the partially observed current week.
  4. Aggregate once: sum played_seconds for the numerator, and take the number of unique (account_id, iso_year, iso_week) tuples for the denominator, not the number of unique accounts.
  5. Emit the four per-week rows as well, and confirm the scalar equals the account-week-weighted mean of the four weekly ratios.

Worked solution (20 min)

  1. Join is_test_account onto the stream frame, drop the test rows, and keep only is_qualified == True.
  2. Build iso_year and iso_week from started_at with .dt.isocalendar(), and a week_start timestamp (Monday 00:00 UTC) for the completeness test.
  3. Select the four distinct (iso_year, iso_week) keys with the largest week_start whose week_start + 7 days is at or before the as-of timestamp.
  4. Numerator: played_seconds.sum()/3600 over those weeks. Denominator: drop_duplicates on (account_id, iso_year, iso_week) and take the row count.
  5. Group by the ISO key for the four per-week rows (hours, account_weeks, ratio), and divide the totals for the scalar.

Expected result: One float equal to total qualified hours divided by the count of distinct (account_id, iso_year, iso_week) pairs, plus a four-row frame whose hours column sums to the numerator and whose account_weeks column sums to the denominator.

Verify it yourself

  • The scalar equals the account_weeks-weighted mean of the four weekly ratios, and does not equal their unweighted mean unless every week has identical account_weeks.
  • The denominator is at most four times the number of distinct qualified accounts in the window, with equality only if every such account streamed in all four weeks.
  • A stream started on 2025-12-30 lands in iso_year 2026, iso_week 1. If it lands in 2025 week 1, the year column was dropped somewhere.
  • Leaving test accounts in raises the numerator and the denominator together, so the ratio barely moves. Verify the exclusion on the two counts, not on the ratio.

Follow-up

  • A profile-level version of this metric reads lower per unit than the account-level one. Which would you use for a personalisation readout, and what does each unit actually aggregate?
  • Offline playback is uploaded in bulk days after it happened. What does that do to the most recent complete week, and how would you decide when a week is safe to publish?
  • How would this metric move if the qualification threshold rose from 30 to 60 seconds, separately for a short-form-heavy and a long-form-heavy catalogue?

Solve a problem involving data structures, such as reversing a linked list.

Medium · sql and data manipulation

Approach

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

Follow-up

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

Can you explain how a hash table works and its time complexity?

Medium · sql and data manipulation

Approach

  1. Say which table is the grain you start from, and join outward from it.
  2. Check whether any join is one-to-many before aggregating, or the sums inflate.
  3. State the window function and its partition and ordering out loud before writing it.

Follow-up

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

Weekly engaged accounts from qualified streams on distinct days

Easy · aggregation · active accounts · qualification threshold

fct_stream has one row per playback with account_id, started_at (UTC), played_seconds, is_qualified (true when played_seconds >= 30) and event_date, a date partition key derived from started_at. dim_account has account_id and is_test_account. Write one query returning, for the seven days ending 2026-03-31 inclusive, the count of weekly engaged accounts: distinct non-test accounts with at least one qualified stream on two or more distinct UTC dates inside that window. Return a single row. Count at the account level, not the profile level.

Approach

  1. Filter fct_stream on event_date BETWEEN '2026-03-25' AND '2026-03-31' and is_qualified = true. Filtering on started_at alone leaves the engine no partition to prune, so it reads every day the table holds; event_date is the partition key and is what belongs in the predicate.
  2. Drop test accounts before the date count, with a join or semi-join to dim_account on is_test_account = false. Excluding them afterwards is too late, because a test account that streamed on two days has already been counted as engaged.
  3. GROUP BY account_id and take COUNT(DISTINCT event_date) AS active_days. The distinct is the entire metric: an account with forty qualified streams inside one calendar day has one active day.
  4. Filter HAVING COUNT(DISTINCT event_date) >= 2, then wrap in an outer COUNT(*). The group-by has already made account_id unique, so an outer COUNT(DISTINCT account_id) adds a sort for nothing.
  5. Sanity-bound the answer before reporting it: it must be no larger than the count of distinct non-test accounts with any qualified stream in the window.

Worked solution (20 min)

  1. Compute the ceiling first: COUNT(DISTINCT account_id) over non-test accounts with any qualified stream in the window.
  2. Build a CTE of (account_id, COUNT(DISTINCT event_date) AS active_days) over the filtered rows.
  3. Select COUNT(*) from that CTE where active_days >= 2.
  4. Re-run the final filter at >= 1 and >= 3 to see the shape of the distribution and confirm the metric is not being carried by accounts sitting exactly on the boundary.

Expected result: A single integer. It must satisfy count(>=3) <= count(>=2) <= count(>=1), where count(>=1) is the ceiling computed in step one.

Verify it yourself

  • The three thresholds are monotone: raising the active-days requirement never raises the count.
  • Removing the is_test_account filter raises the count or leaves it unchanged, never lowers it.
  • No account_id appears more than once in the pre-aggregate CTE.

Follow-up

  • If you counted distinct dates per profile and then rolled up to the account, would the number rise or fall, and which unit does the metric actually want?
  • An account plays one 40-second track at 23:58 and another at 00:03. That is two distinct UTC dates and therefore engaged. Is that the intent, and what would you change if not?
  • Offline plays upload in bulk several days late with started_at backdated. Which part of this query silently changes when they land?

Propose a data-driven strategy to improve product adoption.

Medium · product sense and metrics

Approach

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

Follow-up

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

Given a dataset, how would you identify trends and anomalies?

Medium · product sense and metrics

Approach

  1. Restate the decision this analysis has to support, and who acts on the answer.
  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?
  • How would you detect that the metric is being gamed rather than genuinely improving?

How would you approach a project to reduce churn for a subscription service?

Medium · product sense and metrics

Approach

  1. Decompose the metric into the rates that drive it, and say which one you would check first.
  2. 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

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

What steps would you take to analyze user engagement data?

Medium · product sense and metrics

Approach

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

Follow-up

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

Discuss how you would design an experiment to test a new feature.

Medium · a/b testing and experimentation

Approach

  1. State the primary metric and the minimum effect worth shipping, then size the test.
  2. Say whether units interfere with each other, and switch design if they do.
  3. Name the guardrails that would stop a launch even on a positive primary result.

Follow-up

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

Explain the difference between supervised and unsupervised learning.

Medium

Approach

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

Follow-up

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

Define success before a startup-latency infrastructure change

Easy · metric design · quality metrics · guardrails · mix effects

An infrastructure change is expected to cut startup_latency_ms on tv_app playback. You must define success before the rollout. Available: fct_stream (startup_latency_ms, rebuffer_seconds, played_seconds, peak_bitrate_kbps, end_reason, start_source, device_type, cdn_pop, network_type). Propose one primary outcome metric, the latency statistic you will report and at which quantile, and two guardrails. State how you will stop a mix shift across device_type and cdn_pop from reading as an improvement, and name one way a latency win could be bought rather than earned.

Approach

  1. Separate the input from the outcome out loud: startup_latency_ms is the thing the change moves, but success is whether consumption improved, so the primary metric is qualified hours per active account-week on tv_app and latency is the mechanism metric that explains it.
  2. Choose the latency statistic for the shape of the distribution: startup latency is right-skewed with a long tail from cold caches and poor networks, so report p95 and p99 rather than a mean, because the mean moves with tail mass that a handful of streams contribute and the tail is where abandonment lives.
  3. Kill the mix effect by construction: compute the latency quantiles inside (device_type, cdn_pop, network_type) cells and aggregate with cell weights fixed from a pre-period, so that a rollout reaching wifi and well-provisioned points of presence first cannot show a win that is entirely composition.
  4. Guardrail one on how a latency win is bought: peak_bitrate_kbps and the rebuffer ratio, sum(rebuffer_seconds)/sum(played_seconds) with played_seconds = 0 rows excluded from both sides, because starting playback at a lower ladder rung lowers time to first frame and costs picture quality instead.
  5. Guardrail two on what the ratio hides: start-failure rate over streams with end_reason = 'playback_error' and played_seconds = 0, counted separately, since a point of presence that fails before first frame contributes to neither side of the rebuffer ratio and would otherwise report perfectly.
  6. State the exclusion: cut or exclude start_source = 'resume', because resumed playback starts from a warm buffer and a rollout that shifts the resume share moves pooled latency without any engineering change.

Worked solution (20 min)

  1. Write the primary metric with numerator, denominator and window, restricted to device_type = 'smart_tv' and its streaming-stick equivalents, and state that it is the outcome the change is judged on.
  2. Specify the latency readout: p95 and p99 of startup_latency_ms computed within (device_type, cdn_pop, network_type) cells, aggregated with pre-period cell weights, reported daily against the same cells pre-rollout.
  3. Construct one numerical counterexample showing the mix trap: two points of presence with unchanged within-cell latency but a shift in traffic share between them, and compute that the pooled mean moves while every cell is flat.
  4. Write the two guardrails: peak_bitrate_kbps distribution plus rebuffer ratio with the played_seconds = 0 exclusion stated, and start-failure rate over end_reason = 'playback_error'.
  5. State the exclusion rule for start_source = 'resume' and the reason, and write the one-line ship rule combining primary and guardrails.

Expected result: Primary: qualified hours per active account-week on TV devices. Mechanism metric: p95 and p99 startup_latency_ms within (device_type, cdn_pop, network_type) cells with fixed pre-period weights. Guardrails: peak_bitrate_kbps together with the rebuffer ratio excluding played_seconds = 0, and a separately counted start-failure rate over end_reason = 'playback_error'. The bought win is opening at a lower bitrate rung.

Verify it yourself

  • The worked mix counterexample shows every cell flat while the pooled mean moves, which confirms the weighting is doing real work rather than being ceremony.
  • Streams with played_seconds = 0 appear in exactly one metric, the start-failure rate, and in neither side of the rebuffer ratio.
  • The bitrate guardrail is stated as a distribution, not a mean, so a shift of the low tail onto a lower ladder rung is visible.
  • Resume-sourced streams are either excluded or reported as their own cut, so a change in resume share cannot move the headline latency.

Follow-up

  • p99 falls but the mean rises. What do you conclude, and which cut would you look at first?
  • The change only reaches accounts on app versions above a floor. How does that change what your comparison can claim?
  • How large a latency improvement would you need before you expect qualified hours to move at all, and how would you size that before running it?

Involuntary churn share jumped after a dashboard rebuild

Medium · definition-change · churn · late-resolving-data

Involuntary share of gross churn — fct_subscription_period rows with renewal_outcome = 'failed_involuntary' over rows with renewal_outcome in ('cancelled_voluntary','failed_involuntary'), keyed on period_end_ts month — reads 31% for last month against 19% for the three months before. Billing reports no change in decline rates and dunning_attempts per failed period is unchanged. Using fct_subscription_period (period_end_ts, renewal_outcome, payment_status, dunning_attempts, cancel_requested_ts, billing_provider), determine whether involuntary churn actually rose. Deliverable: the corrected month-on-month series and the specific change that produced the step.

Approach

  1. Check the month's maturity before anything else. Periods ending recently still have retries in flight, and a row reading 'failed_involuntary' today becomes payment_status = 'retried_paid' next week. Recompute every one of the last twelve months as of a fixed age — period_end_ts plus the maximum retry window — instead of as of today.
  2. If the step survives age alignment, hunt for a definition change: diff the model or query against the version that produced 19%, and check specifically whether the month is now keyed on cancel_requested_ts rather than period_end_ts, and whether 'refunded' or 'chargeback' rows have entered one side of the ratio.
  3. Settle it with one query rather than a narrative. Run the old definition and the new definition on the same month. Two numbers from one month under two definitions is decisive; two numbers from two months under one definition is not.
  4. If a definition did change, restate history rather than leaving a step in the chart: run the new definition back across all twelve months and publish both series with the cutover marked, so nobody re-discovers this in a quarter.
  5. Cut the horizon-closed series by billing_provider before concluding nothing moved. Card-direct, app-store and carrier billing have different retry mechanics and different success rates, so a mix shift between them moves the ratio with every provider's own rate flat.

Follow-up

  • How would you set the dunning horizon from the data instead of taking billing's stated maximum?
  • Under cancel-at-period-end, the cancellation request and the entitlement end fall in different months. Which timestamp keys this metric, and what does the other choice do to the curve?

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.

Getting an analysis acted on

Work that nobody used is a common and unflattering pattern in data careers, and interviewers probe for it. Have a story about an analysis that changed a decision, and be specific about how you got it in front of the person who could act. Also have one about work that went nowhere, with your reading of why.

How do you approach continuous learning in your field?

Medium · behavioural and stakeholder questions

Approach

  1. Close with what you would do differently, concretely.
  2. Quantify the outcome, including what you would not claim credit for.
  3. Pick a story where you drove the decision, not one where you observed it.

Follow-up

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

Walk through an analysis you shipped that was wrong

Medium · error ownership · data quality · postmortem

Describe a case where you delivered a result that was later shown to be wrong, and it had already been acted on. Cover how the error surfaced, whether you or someone else found it, what the wrong number caused, and what you changed afterwards. Prepare an example whose root cause was a definition, a denominator or a join — not a transcription slip. The interviewer will push on the mechanism, not the apology. Deliverable: a four-minute account that ends with a specific control now running in a pipeline.

Approach

  1. The probe is whether your account has a mechanism in it. Choose an error that generalises — a denominator that silently changed population, a join that fanned rows, a metric partitioned on event_date while offline playback arrived days late and landed in the wrong partition — rather than one that only teaches you to check your typing.
  2. State the blast radius factually and early: which decision was taken, how long the number stood, what it cost. A candidate who softens this is answering a different and easier question, and the interviewer can hear the substitution.
  3. Explain how it surfaced without adjusting who found it. The generalisable detail is why your own checks did not catch it, which is a statement about your checks rather than about your luck.
  4. Name the control you added and where it now lives: a row-count assertion after the fan-out join, a reconciliation that recomputes a closed day after late-arriving offline playback and alerts above a threshold, a denominator assertion inside the query. A fix that lives in a pipeline is different in kind from a resolution to be more careful.
  5. Close with whether the control has fired since, or how you tested that it would. That single sentence is what separates a fix from an intention, and interviewers ask for it when candidates do not offer it.

Follow-up

  • Why didn't your own review catch it? Be specific about what you did check.
  • What class of error would that control still not catch, and what would you add next?
  • Have you found an error in someone else's published analysis since? How did you raise it?

Defend a flat result on a flagship discovery launch

Medium · defending findings · statistical power · experiment readout

A new ranker ran to 50 percent of accounts for four weeks. Your read: qualified hours per active account-week is +0.4 percent with a 95 percent interval of [-0.9 percent, +1.7 percent]. Meanwhile the share of qualified streams with start_source = 'algorithmic_slate' rose six points and the share with start_source = 'search' fell five. The team reads the slate shift as the win and wants to ship. The launch review is Friday. Deliverable: a five-minute verbal position and the one table you put on the screen.

Approach

  1. The probe is whether you can hold a position under social pressure without overclaiming in the other direction. Separate the two claims explicitly: the start-source shift is well measured and real; the hours effect the launch was justified on is not distinguishable from zero at this sample size. Those are different statements and only one is contested.
  2. Do the power arithmetic before the meeting, using the observed per-account variance on a right-skewed hours metric. Arrive able to say "at this n we could not have detected less than X percent", which is a fact, instead of "it didn't work", which is an opinion the room can simply disagree with.
  3. Show the substitution as arithmetic, not interpretation: decompose treatment hours by start_source and show slate hours rising by approximately what search hours fell. A start-source mix shift with no change in total is exactly what displacement looks like, and the decomposition sums to the total so there is nothing to argue about.
  4. Refuse the symmetric overclaim. The interval's upper bound is commercially meaningful, so "the ranker does nothing" is not supportable either; say that out loud, because it is what makes the rest of your position credible.
  5. Offer the falsifiable next step with a price: a longer read powered for the hours effect, or CUPED on a pre-period consumption covariate measured before assignment, with the required account-weeks stated. Put the disagreement on the pre-registered metric, not on the team's judgement.

Follow-up

  • The PM argues start-source mix is a leading indicator of retention. How would you test that claim, and how long would it take?
  • Suppose the interval had been [+0.1 percent, +1.9 percent]. Does your position change, and by how much?
  • The decision goes against your read and the ranker ships. What do you do on Monday?