cswork / libraryOpen practice workspace

Interview guides · Itlize Global

Itlize Global Data Scientist Interview Questions & Guide 2026

Modeling drills for a Itlize Global data scientist interview: baselines, regression interpretation, class imbalance, model defense.

The 60-second brief

A Data Scientist at Itlize Global plays a pivotal role in harnessing data to drive strategic decision-making and enhance products. By leveraging statistical analysis, machine learning, and data visualization techniques, you will generate insights that directly impact business outcomes and user experiences. This position is crucial in ensuring that the company remains competitive in a rapidly evolving data landscape, allowing teams to innovate and refine products that meet user needs effectively.

Nearly every loop contains a round whose deliverable is a recommendation to someone non-technical. Practise stating a conclusion, the confidence attached to it, and the cost of being wrong in each direction, because that triple is the artifact being graded.

Focus areas

  • Correct discovery slates for position bias
  • Define a qualified stream and defend it
  • Separate release-calendar spikes from underlying trend

Overview

In this role, you will engage with complex datasets, collaborate with cross-functional teams, and contribute to projects that span various domains, from product development to operational efficiency. Your work will not only influence the technical aspects but will also shape the strategic direction of the organization, making this role both challenging and rewarding. Candidates can expect to work on cutting-edge tools and technologies in a dynamic environment that values data-driven decision-making.

The Itlize Global interview process

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

Initial 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

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

Behavioral Interviews

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

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.

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.

Ignoring interference between units in a marketplace experiment

Ask whether one unit's treatment can change another unit's outcome through shared inventory, a matching pool, a social graph or a common budget. Where it can, randomise at a level that contains the spillover, such as region or time slice, and say explicitly what that costs you in statistical power.

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.

Questions & practice

Describe the time complexity of common sorting algorithms.

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. Frame the prediction: the label, the moment of prediction, and the action it triggers.

Follow-up

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

Can you explain the concept of overfitting and how to prevent it?

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

  • Where could label leakage enter this setup?
  • 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?

Write a SQL query to extract the top 10 customers based on sales data.

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. Check whether any join is one-to-many before aggregating, or the sums inflate.
  3. Say which table is the grain you start from, and join outward from 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?

Net revenue per active account-month without fanning out periods

Hard · fan-out · revenue recognition · grain

fct_subscription_period has account_id, period_start_ts, period_end_ts, net_amount_usd and payment_status. fct_stream has account_id, started_at, played_seconds and is_qualified. Compute net revenue per active account-month for March 2026: the numerator is subscription revenue over periods with payment_status in ('paid','retried_paid'), recognised pro rata by the days of each period falling inside March; the denominator is distinct accounts with at least one qualified stream in March. A colleague's draft joins the two tables on account_id, filters streams to qualified March rows, and sums net_amount_usd; its numerator is roughly forty times too large. Explain the factor and write the correct query.

Approach

  1. Name the mechanism and decompose the number. The join is one period to many streams, so each period row is duplicated once per matching stream and its net_amount_usd is added that many times: the naive sum equals the un-prorated period sum weighted by each account's March qualified-stream count, which is the net_amount_usd-weighted mean stream count over the accounts the inner join keeps. The distance from there to the correct numerator has two further parts, in opposite directions — pro-rating shrinks the correct figure, while the inner join has dropped every period belonging to an account that streamed nothing in March. A weighted mean near thirty streams against a pro-rata factor near 0.75 is what puts the draft around forty times high; the number is not arbitrary, which is why it looks plausible enough to ship.
  2. Adopt the rule that produces the fix: two fact tables never meet at row grain. Aggregate each to account grain first and join the aggregates, or — better here — do not join at all, because the numerator and the denominator are independent scalars that share no key.
  3. State the interval convention before writing the arithmetic. Treating periods as half-open [period_start_ts, period_end_ts) makes consecutive periods tile without overlap; overlap_days = GREATEST(0, LEAST(period_end_ts, DATE '2026-04-01') - GREATEST(period_start_ts, DATE '2026-03-01')) in days, and the contribution is net_amount_usd * overlap_days / total_days_of_period. An annual period contributes roughly 31/365 of its amount.
  4. Build the denominator on its own: COUNT(DISTINCT account_id) FROM fct_stream WHERE is_qualified AND started_at >= '2026-03-01' AND started_at < '2026-04-01'. Do not restrict it to paying accounts — the metric deliberately holds subscription and advertising revenue to one engaged-account denominator, and filtering to payers is what makes a tier migration look like two unrelated numbers moving.
  5. State the closing rule with the result: the month must be at least 45 days closed, because refunds and chargebacks are recorded against periods late and an open month always reads high.

Worked solution (35 min)

  1. Reproduce the bug deliberately: compute the naive joined sum, and beside it the un-prorated SUM(net_amount_usd) over the same period rows restricted to accounts with at least one qualified March stream. Their ratio is the fan-out multiple, and it is the only ratio in this problem that has a closed form.
  2. Write the overlap expression and verify that one period's contributions, summed across every month it touches, reconstruct its net_amount_usd exactly.
  3. Compute the denominator independently and combine the two as one-row CTEs joined with CROSS JOIN, so neither side can fan out the other.
  4. Re-run for February and March and confirm no revenue is counted in both, which is the boundary test for the half-open convention.

Expected result: A single row of numerator_usd, active_accounts and their quotient. Each period's pro-rata contributions summed over all months it spans reconcile to its net_amount_usd within floating-point rounding.

Verify it yourself

  • Naive joined sum divided by the un-prorated SUM(net_amount_usd) over the same period rows — restricted to the accounts the inner join keeps, meaning those with at least one qualified March stream — equals the net_amount_usd-weighted mean qualified-stream count over those accounts. Do not expect that identity against the correct numerator: that one is pro-rated to March and also carries the periods of accounts that streamed nothing, so the two differ by more than a single factor.
  • A period's contributions across every calendar month it touches — thirteen months for an annual period that does not begin on the 1st — sum to its net_amount_usd.
  • No period contributes anything to March when period_end_ts <= 2026-03-01 or period_start_ts >= 2026-04-01.

Follow-up

  • One account holds two overlapping periods after a plan migration. Whose revenue counts for March, and does your pro-rata still sum to each period's own total?
  • Advertising revenue belongs in this numerator. What grain does it arrive at, and what breaks in your query when you add it?
  • How would you turn this into a monthly time series without rewriting the date literals, and what would you do about periods that span three months?

Given a dataset, how would you determine the key drivers of customer churn?

Medium · product sense and metrics

Approach

  1. State what result would change your recommendation, so the answer is falsifiable.
  2. Name one primary metric, then the guardrail that stops it being gamed.
  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?

Provide a framework for approaching a data science project in an unfamiliar domain.

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. Restate the decision this analysis has to support, and who acts on the answer.
  3. Fix the population and the time window before naming any metric.

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?

If you had to analyze the performance of a marketing campaign, what metrics would you consider?

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. Fix the population and the time window before naming any metric.
  3. State what result would change your recommendation, so the answer is falsifiable.

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 do you prioritize tasks when working on multiple data projects?

Medium · product sense and metrics

Approach

  1. Fix the population and the time window before naming any metric.
  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?
  • What would you do if the primary metric and the guardrail moved in opposite directions?

How would you structure an experiment to test a new product feature?

Medium · a/b testing and experimentation

Approach

  1. Name the randomisation unit first; it decides the variance and what the test can detect.
  2. Say whether units interfere with each other, and switch design if they do.
  3. State the primary metric and the minimum effect worth shipping, then size the test.

Follow-up

  • How would you handle interference between treated and control units?
  • What would you do if you could not randomise at all?

Explain how you would approach a data analysis project from start to finish.

Medium

Approach

  1. Say what you would check first and why it is the highest-information step.
  2. State your assumptions explicitly before working the problem.
  3. Clarify what is being asked and what a complete answer would contain.

Follow-up

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

Value the home slate when the counterfactual is unobservable

Medium · metric design · proxy bias · position bias · recommendation evaluation

Define how you would measure what the algorithmic home slate is worth. You have fct_impression (impression_id, slate_id, slate_position, surface, viewport_visible_ms, ranker_version, is_exploration_slot, logging_propensity, was_clicked) and fct_stream (impression_id, start_source, started_at, played_seconds, is_qualified). Deliverable: name the quantity you actually care about, say plainly whether it is observable, then give the proxy you would report, its direction of bias with the reasoning, and what would have to be true for the proxy to be unbiased.

Approach

  1. Name the estimand precisely and then concede it: incremental qualified hours caused by the slate, defined as hours consumed with the slate minus hours the same accounts would have consumed without it in the same window. The second term never appears in any table, so no query answers this and the honest first sentence says so.
  2. Give the naive proxy and its bias direction: qualified streams with start_source = 'algorithmic_slate' joined to fct_impression on impression_id within a fixed attribution window, which is biased upward because it counts every play the account would have reached through search, resume or a direct link, and the upward bias is largest exactly for head content the account already intended to play.
  3. Give the better proxy and state its precondition rather than assuming it: a propensity-weighted play rate computed only on rows with is_exploration_slot = true, where logging_propensity is populated, which is unbiased for the logging policy only if propensities are known, every item had non-zero probability of being shown, and no unlogged feature drove both exposure and play. Outside the exploration slots positivity fails silently, so the estimate does not extend to items the logger never demotes.
  4. Bound the naive proxy instead of abandoning it: compare slate-attributed qualified hours against the same accounts' non-slate hours in a matched pre-period, which gives an upper and a crude lower figure and turns a single unfalsifiable number into a range with a stated interpretation.
  5. State what each method cannot say: an offline ranking metric says nothing about downstream retention, interleaving picks a winner between rankers without producing an hours or revenue figure, and only a slate-off arm answers the value-of-the-slate question, which is usually not shippable, so the answer that goes in the memo is the exploration-slot estimate plus the naive range with the bias direction written next to it.
  6. Pin the attribution mechanics so the proxy is at least reproducible: a fixed window from rendered_at to started_at, a documented tie-break when the same content_version_id appears in two slates, and a requirement that viewport_visible_ms is above zero before an impression counts as exposure at all.

Worked solution (30 min)

  1. Write the estimand as a difference of two terms and mark which term exists in the warehouse and which does not, in one line each.
  2. Write the naive attributed-hours metric fully: join fct_stream to fct_impression on impression_id, restrict to is_qualified and start_source = 'algorithmic_slate', fixed window, viewport_visible_ms > 0, and state the bias direction as upward with the reason in the same sentence.
  3. Write the propensity-weighted estimator on is_exploration_slot rows and list its three preconditions explicitly: known propensities, positivity, and no unlogged confounder of exposure and play.
  4. Construct the bounding comparison: matched pre-period non-slate hours for the same accounts, and state what the resulting range does and does not license you to claim.
  5. Write the two or three sentences that would go in the memo, with the bias direction attached to the number rather than in a footnote.

Expected result: The estimand is incremental qualified hours attributable to the slate, which is not observable because the no-slate term does not exist. Reported proxy: propensity-weighted play rate on exploration slots, unbiased only under known propensities, positivity and no unlogged confounding, presented alongside slate-attributed qualified hours labelled as an upper bound, with the matched pre-period comparison supplying the range.

Verify it yourself

  • The answer contains an explicit sentence saying the quantity of interest is not measurable from logged data, before any proxy is offered.
  • Each proxy carries a bias direction, and the direction is justified by a mechanism rather than asserted.
  • The three preconditions for the propensity-weighted estimate are named, and positivity is identified as the one that fails silently outside exploration slots.
  • The attribution rule fixes a window, a tie-break and an exposure condition, so two analysts computing it get the same number.

Follow-up

  • How large would you make the exploration slot fraction, on which surface, and how would you bound its cost in engagement before proposing it?
  • Slate-attributed hours rise 8 percent after a ranker change while total qualified hours are flat. What is the most likely explanation and which metric distinguishes it?
  • Your propensity-weighted estimate has an enormous variance because a few rows carry small logging_propensity. What do you do, and what does the fix cost you in bias?

Consumption fell the week a new ranker shipped

Hard · confounding · catalogue-supply · causal-inference

Qualified hours fell 4% in the seven days after a home-row ranker shipped to 100%, and a rollback is being demanded for tomorrow. You have fct_stream (played_seconds, is_qualified, content_version_id, start_source, started_at, play_territory), fct_impression (ranker_version, content_version_id, rendered_at), dim_content_version (content_id, parent_id, rights_expires_at, available_territories, catalogue_added_ts, is_active_version), and no holdout — the rollout went from 5% straight to 100%. Determine whether the ranker caused the fall. Deliverable: a defensible causal read, or an explicit statement of what cannot be concluded and what you would run instead.

Approach

  1. Check supply before demand. Sum the prior period's qualified hours on content_version_ids whose rights_expires_at falls inside the window, whose is_active_version flipped, or whose available_territories lost a territory. If titles carrying several points of hours left the catalogue that Monday, the fall is partly accounted for before the ranker is even discussed.
  2. Separate the mechanically unavailable from the merely deranked. Hours lost on items still available but no longer surfaced belong to the ranker; hours lost on items that cannot legally be served do not, and no ranking change recovers them. Only the first category is evidence for a rollback.
  3. Recover a comparison the rollout destroyed. With no holdout, use the 5% phase as a pre-period and territories unaffected by the expiry as a control, running difference-in-differences with the expiry as the treatment. State the parallel-trends assumption out loud and test it on the four pre-window weeks; abandon the estimator if it fails rather than reporting it with a caveat.
  4. Measure displacement instead of gross hours. For accounts whose usual items left, did total hours fall or did they substitute within the catalogue? Fully substituted removal costs nothing in hours and shows up only in the affected rights holder's payout, which is a different problem with a different owner.
  5. Ask separately what the ranker did to exposure: impression share by content_id under each ranker_version, and top-1% exposure concentration. A ranker that concentrates exposure can depress hours through a mechanism nobody has named yet, and this is what distinguishes that story from the rights story.
  6. Refuse the causal claim the rollout cannot support. Say plainly that a 5%-to-100% ramp across a confounded week yields no unbiased effect estimate, and propose the switchback or re-randomised holdout that would, with its cost stated.

Follow-up

  • Design the switchback: slice length, burn-in long enough to clear carryover on a personalised surface, and how the standard error handles correlation between adjacent slices.
  • If the rollback is ordered regardless of your analysis, what do you measure during the rollback to get a second, independent read?

Suggested practice checklist

For someone who has spent the last year in notebooks, dashboards or modelling work and has not written raw SQL under time pressure. The first four days rebuild query fluency against a fixture you control and can verify by hand; the last three attach that fluency to the rest of the loop.

Day 1 — Build a fixture you can check answers against

  • Create a local Postgres or SQLite database with four tables (users, sessions, events, orders) holding roughly 200 rows you generated yourself, so you know the contents well enough to predict every result.
  • Deliberately seed the cases that break queries: a user with no sessions, a session with no events, two orders sharing a timestamp, a NULL in one join key, and one duplicated user row.
  • Before writing any SQL, hand-compute five answers on paper (how many users placed at least one order, median orders per ordering user, and three others) and save them as the ground truth for the week.

Deliverable: A one-command seed script plus a text file of five hand-computed answers to grade every later query against.

Day 2 — Joins, filters and NULL semantics

  • Answer "which users have no orders" three ways (LEFT JOIN with IS NULL, NOT EXISTS, NOT IN) and confirm that the NOT IN version returns zero rows once the subquery contains a NULL, because the comparison is never TRUE.
  • Reproduce the LEFT JOIN that silently collapses to an inner join by putting a right-table predicate in WHERE, then fix it by moving the predicate into the ON clause, and record both row counts.
  • Create a fan-out bug on purpose by joining orders to order_items and summing the order total, then correct it with a pre-aggregated subquery and explain in one line which table changed the grain.

Deliverable: One annotated .sql file holding the three join traps, each with the wrong result and the corrected result side by side.

Day 3 — Window functions and frames

  • Write three window queries against the fixture: a running order total per user, the rank of each order within its user by value, and the day gap to that user's previous order, then check each against the day-one ground truth.
  • Run ROW_NUMBER, RANK and DENSE_RANK over a column containing ties, print all three side by side, and write one sentence on when each is the correct choice.
  • Switch one query from the default frame (RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, which is what you get when ORDER BY is present and no frame is written) to ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, and explain why the output differs only when the ORDER BY column has duplicates.

Deliverable: Three verified window queries plus a short note explaining the RANGE versus ROWS difference in your own words.

Day 4 — The four analytical query patterns

  • Write a monthly retention grid: first order month per user, then months-since-first as the column, and verify that month zero equals the cohort size exactly.
  • Sessionize the events table under a 30-minute inactivity rule using LAG plus a cumulative sum over a new-session flag.
  • Build a four-step funnel that counts distinct users rather than events at each step, and state the rule you applied to a user who reaches step three without ever logging step two.

Deliverable: One file with the retention, sessionization and funnel patterns, each carrying a one-line note on the assumption it bakes in.

Day 5 — Write SQL the way you will have to write it live

  • Set a 12-minute timer and solve three medium prompts in a plain editor with no execution and no autocomplete, then run them and tally syntax errors separately from logic errors.
  • Narrate one solution aloud while writing it, stating the grain of each intermediate result (one row per user, one row per user-day) before you type its body.
  • Rewrite your slowest solution as a CTE chain where every CTE name states its grain, and time yourself re-solving it from blank.

Deliverable: A recording of one narrated solution plus an error tally that separates syntax from logic.

Day 6 — One day for everything that is not SQL

  • Write the preconditions of the two-sample t-test from memory, then check them: independent observations, and a difference in means whose sampling distribution is approximately normal, which at large sample sizes follows from the central limit theorem rather than from normality of the raw values.
  • Write the difference between an odds ratio from logistic regression and a relative risk, and state the condition under which the two are close (low outcome prevalence).
  • Prepare a 90-second answer to "how would you know this model is any good" that names the metric, the baseline you would beat, and the cost of the errors you care about.

Deliverable: One page of notes covering test preconditions, the odds-ratio caveat and the model-quality answer.

Day 7 — Full loop rehearsal

  • Run a 45-minute mock with someone willing to interrupt: 20 minutes of SQL, 15 minutes defining a metric, 10 minutes on a past project.
  • Re-solve from blank the two queries you were slowest on this week and compare the times against day five.
  • Write a five-line answer to "walk me through a project" that puts a number in the first sentence and names the decision the work changed.

Deliverable: Mock feedback notes plus a timed project narrative you can deliver without reading it.

Ownership when the result is inconvenient

Sometimes the honest read is that the initiative did not work, and the person who commissioned the analysis was hoping otherwise. Interviewers want to know whether you softened it. Prepare the case where you delivered an unwelcome result, how you presented the uncertainty without hiding behind it, and what the team did next.

What motivates you to excel in your work as a data scientist?

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. Name the disagreement or constraint, and how you resolved it with evidence.

Follow-up

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

State the impact of your last year without inflation

Hard · self-assessment · attribution · counterfactual reasoning

You are asked what your work was worth over the last year. Two candidates are on the table. First: a dunning-schedule change you analysed, shipped in March with no holdout, after which the involuntary share of gross churn fell three points. Second: a metric-definition change you drove, which nobody can attribute revenue to. Deliverable: the impact claim you make for each, the counterfactual attached to each, and which one you lead with in a performance review — with the reason.

Approach

  1. The probe is whether you apply the same causal standard to your own work as to a product experiment. Attach the counterfactual before the claim: involuntary share of gross churn responds to card-updater coverage, billing_provider mix, retry schedules and the dunning horizon you read it at, any of which can move three points with the schedule change contributing nothing.
  2. Say which evidence would separate those, then say plainly which you actually have. A staggered rollout by billing_provider, a holdout, or at minimum a flat pre-period series would each support a different strength of claim; with none of them, the honest claim is a contribution to a favourable movement, stated as such.
  3. Check the classification itself before claiming the movement is real: the split between cancelled_voluntary and failed_involuntary must be computed only after the dunning horizon has closed for every period in the month, or retries still in flight are counted as churn and the share reads too involuntary in one direction and corrects in the other.
  4. Price your contribution rather than the outcome. The value of analysis that changed a decision is the decision's delta multiplied by the probability the decision would not have been taken without it, and being explicit about that second factor is most of what honesty means here.
  5. Make the definition-change claim concrete rather than apologetic: name the decisions that would have been taken on the wrong number, the reports it reconciled, the recurring argument it closed, with dates. Then lead with whichever claim survives questioning, not whichever carries the larger number, because an inflated first claim makes the second unbelievable.

Follow-up

  • Your manager writes up the churn improvement and credits it to you. Do you correct it, and to whom?
  • How would you have designed the March rollout so that attribution was possible, at what cost in delay?
  • Name something you worked on last year that had no impact, and say what you learned from that rather than from the wins.

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?