cswork / libraryOpen practice workspace

Interview guides · Guardant Health

Guardant Health Data Scientist Interview Questions & Guide 2026

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

The 60-second brief

As a Data Scientist at Guardant Health, you will play a crucial role in transforming complex data into actionable insights that drive innovation in cancer diagnostics and therapeutics. This position is vital to the organization as it combines statistical analysis, machine learning, and domain expertise to enhance our understanding of patient outcomes and treatment efficacy. Your contributions will impact not only our product development but also the lives of patients by enabling more personalized and effective treatment options.

Most of the loop measures decision-making under uncertainty rather than recall. You are scored on whether you state your assumptions, commit to an estimate you can defend, and say explicitly what evidence would change it.

Focus areas

  • Risk-adjust outcomes before comparing providers or panels
  • Separate censoring from events in time-to-event models
  • Build member-month denominators from overlapping coverage spans

Overview

The role encompasses working on significant projects that involve analyzing large datasets derived from genomic tests, collaborating with cross-functional teams, and utilizing advanced modeling techniques. Given the complexity and scale of the data involved, you will face challenges that require both technical proficiency and creative problem-solving. This is an exciting opportunity to be at the forefront of precision medicine, making strategic contributions that resonate throughout the healthcare continuum.

The Guardant Health interview process

Guardant Health candidates report 6 rounds · ≈ 4-6 weeks. The stages below are what candidates describe, not a published process.

Initial Screening

Whoever runs this call is usually not a practitioner. They take notes, and a hiring manager skims those notes later, so the real question is whether your work survives being written down by someone outside the field. Test every project sentence against that: could a non-specialist repeat it correctly without knowing what a propensity score is? Carry a plain-language version of each project and one reason you want this particular role that you could not copy onto another application. Vagueness at this stage reads as inexperience, even when the underlying work was genuinely deep.

What to demonstrate

  • Whether a non-specialist can restate your projects accurately, since their paraphrase is what reaches the hiring manager
  • Whether your reason for wanting the role points at the work itself rather than the company's reputation
  • Whether your language signals the level being screened for: what you decided yourself versus what you were handed

How to prepare

  • Write a two-sentence, jargon-free version of each major project: the question nobody could answer, and the decision your work changed. Read it to someone outside data and have them repeat it back
  • Point your 'why this role' answer at something concrete in the job description or the product surface you would be working on, and keep it to two sentences
  • Have two questions ready about measurement: which metric the team is held to, and who acts on an analysis once it lands

Technical Assessment

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

What to demonstrate

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

How to prepare

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

Behavioral Interview

Most of the weight in this round sits on the disagreement questions. Data work routinely produces an answer someone senior did not want, and the interviewer is trying to learn what you do in that hour. Both failure modes are common: folding as soon as a director pushes back, and treating the pushback as ignorance to be corrected with a better chart. A strong answer usually contains a specific thing the other person knew that you did not, and describes how you found out whether it changed the conclusion.

What to demonstrate

  • Whether you can state the other side's argument accurately before you explain why you disagreed
  • What you treated as evidence during the disagreement, such as a rerun under their assumption or a holdout check, rather than persuasion technique
  • Whether you distinguish being overruled from being wrong, and can give an example of each

How to prepare

  • Write out one disagreement where you turned out to be wrong, and say what in the data misled you. Candidates prepare the story where they were right, and the follow-up asks for the other one.
  • For your main disagreement story, be ready to say what result would have made you drop your position. If no such result exists, you were not arguing from the data.
  • Practise stating the opposing position out loud in one sentence the stakeholder would accept, then continue the story.

Case Studies

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

What to demonstrate

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

How to prepare

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

Final Interview

A loop is not scored one interview at a time. The people you meet compare notes afterwards, usually in a meeting you are not in, and the outcome turns on what each of them can say about you when asked. That rewards something other than survival: every room needs one specific thing worth repeating, and none of them can contradict another. The common way to lose is to tell the same project four times with different numbers in it, or to be uniformly fine in a way that leaves nobody with anything to argue for.

What to demonstrate

  • Whether your account of a project survives being told twice, with the same scale, the same metric definition and the same numbers each time
  • Whether each interviewer leaves with one concrete claim they could make on your behalf later, rather than an absence of complaints
  • Whether a question you already answered in an earlier room gets the same answer at the same depth, without visible impatience

How to prepare

  • Write a one-page fact sheet for your two or three main projects that fixes the numbers you will quote: rows of data, the metric as a single sentence, the effect you measured and how long the work took. Say them aloud from the sheet until they come out identical every time
  • For each kind of room you expect, decide the one sentence you want that interviewer repeating in a debrief, then check during the mock that you said it outright instead of implying it
  • Rehearse answering the same project question twice in one sitting, the second time as though you had not just answered it, because the thing that needs fixing is the flatness that creeps into a repeated story

Offer Discussion

An extra round usually exists because something is still open after the standard loop: a skill the earlier interviews did not sample, a level decision, or two interviewers who disagreed. It is rarely a rerun of what you already did well. Ask the recruiter who you are meeting, what function they sit in, and how long the session runs. That is an ordinary scheduling question, and the answer changes what you should prepare. What separates a strong candidate here is treating the round as a fresh evaluation with its own bar, rather than assuming earlier performance carries you through or sinks you.

What to demonstrate

  • Whether you can answer well on ground the earlier rounds did not cover, without leaning on what you already said to someone else
  • Consistency of the facts in your stories: the same sample size, timeframe, team size and scope of your own role as in earlier conversations
  • How you handle an unfamiliar format live, including whether you ask what kind of answer is wanted before producing one

How to prepare

  • Ask the recruiter for the interviewer's function, the length, and whether to expect a coding surface, a discussion, or a presentation. Preparing for a 30 minute conversation with a partner team is not the same work as preparing for a 60 minute technical block.
  • Write out what each earlier round actually covered, then list the two or three areas nobody probed. That gap is the most likely subject of the extra round.
  • Re-read the numbers in the project stories you have already told, so a second telling does not quietly contradict the first.

Where candidates lose points

Reading the most recent months of a claims-based series as real

Claims incur before they are reported and paid, so recent incurred months are systematically undercounted until runout completes. The lag is not uniform: pharmacy adjudicates in days, professional claims in weeks, inpatient facility claims in months. That means recent data is both too low and mix-shifted toward cheap services, which reads as a cost improvement and a utilisation drop at once. The fix is to hold the last three incurred months back or apply completion factors, and to state the paid-through date on every chart.

Ignoring clustering by provider, facility, or site

Patients within a provider panel, and subjects within a trial site, are correlated on both case mix and practice pattern. Standard errors computed as if observations were independent are too narrow by roughly the design effect, 1 + (m - 1) * ICC, where m is the average cluster size. With 50 patients per provider and an intracluster correlation of only 0.02, variance is understated by about a factor of two, which manufactures significant provider differences out of noise. Cluster-robust errors or a random intercept per provider, and cluster-level randomisation when you design the test, are the corrections.

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.

Building features from data that postdates the prediction time

Check every feature against the timestamp at which the model would actually score, and drop anything computed from a window that includes or follows the label event. For a forecasting use case, split train and test by time rather than at random, and split by entity when the same entity recurs.

Questions & practice

How would you approach creating a predictive model for patient outcomes?

Medium · machine learning and modelling

Approach

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

Follow-up

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

Collapse claim versions before summing allowed amounts by member

Easy · claim versioning · groupby · deduplication

You are given medical_claim_line as a pandas DataFrame: claim_line_id, claim_id, claim_version, frequency_code (1 original, 7 replacement, 8 void), member_id, service_start_date, procedure_code, allowed_amount, claim_status. Return total allowed_amount per member for service dates in one stated calendar month, counting each claim once at its surviving version and excluding any claim whose surviving version is a void. Multi-line claims must keep every line of that surviving version. Output columns: member_id, allowed_amount, sorted descending. Do not deduplicate on claim_id alone.

Approach

  1. Separate the two grains out loud before writing code: versions live at the claim level, dollars live at the line level. Every bug in this exercise comes from mixing them.
  2. Compute the surviving version per claim with a groupby transform of max over claim_version, then keep the lines whose claim_version equals that value. A transform keeps the frame at line grain, which a sort plus head(1) does not.
  3. Drop whole claims whose surviving version carries frequency_code 8. A void is not a zero-dollar line, it retracts the claim, so filtering rows rather than claims leaves the prior version's lines behind.
  4. Filter to claim_status 'paid' and state the assumption: denied, pended and reversed lines carry an allowed_amount that never became a liability, so including them overstates cost.
  5. Restrict service_start_date to the month boundaries, then groupby member_id and sum. Sort descending and return.

Worked solution (20 min)

  1. Build a max-version lookup per claim_id with groupby('claim_id')['claim_version'].transform('max') and keep rows where claim_version equals it.
  2. From the surviving rows, collect the claim_ids whose frequency_code is 8 and drop those claim_ids entirely.
  3. Filter claim_status to 'paid' and service_start_date into the month window.
  4. Group by member_id, sum allowed_amount, sort descending, reset the index.

Expected result: A two-column frame member_id, allowed_amount. On a claim with versions 1, 7, 7 only the third version's lines contribute; a claim whose latest version is frequency_code 8 appears nowhere. Total allowed is strictly below a naive sum over all rows whenever any claim in the sample was adjusted, and equal to it when none was.

Verify it yourself

  • The distinct claim_id count in your filtered frame equals the count of distinct claim_ids whose surviving version is not a void.
  • The line count you kept for each surviving claim equals that claim's line count at its max version, not 1.
  • A naive sum over every row is greater than or equal to your total, with equality only when no claim has claim_version above 1.

Follow-up

  • A claim has versions 1, 7, 7 where the second replacement has fewer lines than the first. What does your code return and is that correct?
  • How would you handle a claim whose lines span two calendar months at the boundary of the reporting window?
  • The same logic has to run over 400 million lines in a warehouse. What changes, and what stays the same?

Simulate how ignoring clustering inflates the false positive rate

Medium · simulation · design effect · type i error

Simulate a provider-level comparison with no true effect. 40 providers, 60 members each, a continuous outcome with total variance 1 and intraclass correlation 0.02. Randomise providers 20 to 20, not members. Over 5,000 replications, report the share of replications where a two-sample t-test run on all 2,400 individual observations, ignoring provider, returns p below 0.05. Report the same share when the unit of analysis is the 40 provider means. Then state how the first number follows from the design effect 1 + (m - 1) x ICC.

Approach

  1. Decompose the variance explicitly rather than tuning it: provider variance = ICC = 0.02, residual variance = 1 - ICC = 0.98. Draw u_j once per provider and e_ij per member, so the outcome is u_j + e_ij and the correlation between two members of one provider is 0.02 by construction.
  2. Randomise at the provider level. That is the entire mechanism: the treatment indicator is constant within a provider, so in any single replicate the provider intercepts are confounded with the arm, and the naive test reads that confounding as signal.
  3. Vectorise over replications with a (reps, providers, members) array. 5,000 x 2,400 normals is trivial in numpy, and a Python loop is what tempts people to cut replications to 500 and report a number with Monte Carlo noise of plus or minus 0.017.
  4. Predict the answer before running it: design effect = 1 + (60 - 1) x 0.02 = 2.18, naive standard errors are too small by sqrt(2.18) = 1.476, so the rejection rate at nominal 0.05 is about 2 x (1 - Phi(1.96 / 1.476)) = 0.18. Agreement between prediction and simulation is what makes the result a demonstration rather than an anecdote.
  5. Run the provider-mean analysis as the control. Recovering 0.05 there proves the generator is correct and isolates the failure to the analysis unit.

Follow-up

  • How many providers would you need for 80 percent power on a 0.2 SD difference with 60 members each and this ICC?
  • Cluster sizes are unequal in reality. The design effect approximation becomes 1 + ((1 + CV^2) x mbar - 1) x ICC. Which direction does that move your sample size and why?
  • The intervention cannot be withheld from any provider. Sketch a design that still yields a defensible estimate.

Deduplicate claim versions before totalling allowed amounts

Easy · dedup · window functions · claim versions

medical_claim_line holds one row per service line per claim version: claim_line_id, claim_id, claim_version, frequency_code (1 original, 7 replacement, 8 void), member_id, service_start_date, procedure_code, allowed_amount, claim_status and adjudicated_at. Adjusted claims appear more than once, so summing every row double counts them. Return total allowed_amount by procedure_code for service_start_date in Q1 2025, counting only lines with claim_status 'paid' on the surviving version of each claim, which is the highest claim_version per claim_id, and dropping the claim entirely when that surviving version carries frequency_code 8. Resolve survivorship with a window function, not a self-join.

Approach

  1. Resolve survivorship at claim_id, not claim_line_id. Carry MAX(claim_version) OVER (PARTITION BY claim_id) alongside every line and keep lines where claim_version equals it, because a replacement version can contain a different number of lines than the original.
  2. Read the frequency_code of the surviving version only. A frequency_code 8 removes the claim outright; it does not revert payment to the prior version, so a void must delete the claim rather than promote version n-1.
  3. Apply claim_status and the date filter after survivorship is resolved. Filtering paid lines first can strip the surviving version and silently elect a superseded one.
  4. Group by procedure_code and sum allowed_amount, then state the paid-through date on the output because Q1 amounts keep moving until adjudication runout completes.
  5. Sanity check the shrinkage: report how many claim_ids and how many dollars the dedup removed, so the reviewer can see the step did something.

Worked solution (20 min)

  1. Build a CTE that adds surviving_version = MAX(claim_version) OVER (PARTITION BY claim_id) and surviving_freq = the frequency_code of the row at that version, to every line.
  2. Filter to claim_version = surviving_version so all lines of the surviving version survive together.
  3. Drop claims whose surviving_freq is 8, then apply claim_status = 'paid' and service_start_date between 2025-01-01 and 2025-03-31.
  4. Group by procedure_code, sum allowed_amount, and emit the count of distinct claim_ids contributing.
  5. Run the naive SUM over all rows beside it and report the difference as the double count that was removed.

Expected result: One row per procedure_code with summed allowed_amount over surviving, non-voided, paid Q1 2025 lines. A claim with an original and one replacement contributes only the replacement's lines; a claim whose surviving version is a void contributes nothing.

Verify it yourself

  • Deduped total is strictly below the naive paid-and-Q1 SUM taken across all versions whenever at least one claim carries paid Q1 lines on more than one version. If the two totals match on such a claim, the dedup did nothing.
  • For one claim_id known to have three versions, the line count it contributes equals the number of its paid Q1 2025 lines at its highest claim_version, not 1.
  • Let B be the set of claim_ids whose surviving version has at least one paid line with a Q1 2025 service_start_date. COUNT(DISTINCT claim_id) in the output equals the size of B minus the number of claims in B whose surviving version carries frequency_code 8. Comparing instead against COUNT(DISTINCT claim_id) over the whole raw table is not a void test: that gap also absorbs every claim dropped by claim_status or by service date.

Follow-up

  • Two rows share a claim_id and claim_version but differ on adjudicated_at. What do you do, and what does that imply about the extract?
  • How does the query change if the request is allowed_amount by paid_date rather than service_start_date, and which basis does a finance reconciliation want?
  • A void arrives for a claim already published in a closed month. How do you restate without rewriting history in the warehouse?

Count thirty-day unplanned readmissions without counting transfers

Medium · self-join · event streams · exclusions

encounter holds encounter_id, patient_id, facility_id, encounter_type, admit_ts, discharge_ts, admission_type, discharge_disposition, is_planned_admission and index_encounter_id. For inpatient stays discharged between 2025-01-01 and 2025-11-30, return the 30-day unplanned readmission rate overall and by facility_id. Exclude an index stay when is_planned_admission is TRUE or discharge_disposition is transfer_acute, expired, hospice or ama. A qualifying readmission is any unplanned inpatient admission for the same patient with admit_ts after the index discharge_ts and within 30 days of it. One stay can be both a readmission and the next index stay.

Approach

  1. Decide between LEAD and EXISTS explicitly and say why. LEAD over the patient's admission stream gives the literal next stay, so an intervening planned admission hides a later unplanned one. The measure asks whether any unplanned admission fell in the window, which is an EXISTS or a self-join with a range predicate.
  2. Exclude transfers at the index end before anything else. An acute-to-acute transfer closes one encounter and opens another at a different facility_id within hours, so without the transfer_acute exclusion the facilities that move the sickest patients out look the worst.
  3. Apply the index exclusions as a set, including stays with NULL discharge_ts, which are still open and have no measurable window.
  4. Stop the denominator early enough that every index stay had a full 30 days of observation plus encounter lag. That is why the window ends 2025-11-30 rather than at year end.
  5. Compute the rate at stay level, not patient level, then compare the raw facility rates against an observed-over-expected framing before anyone publishes a ranking.

Follow-up

  • A patient has three stays ten days apart. How many index stays and how many readmissions, and why does the answer depend on the stated rule?
  • Which comparison would you publish across facilities, raw rate or observed over expected, and what does risk adjustment still fail to fix?
  • index_encounter_id already exists on the table. Would you trust it, and how would you audit it against your own logic?

Given a dataset with missing values, outline your strategy for handling them.

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

How do you prioritize your work when faced with multiple deadlines?

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. Restate the decision this analysis has to support, and who acts on the answer.

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?

What statistical methods do you find most effective in your analyses?

Medium

Approach

  1. Work from the decision backwards to the evidence you would need.
  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?

Can you explain the concept of data drift and how you would verify it?

Medium

Approach

  1. Work from the decision backwards to the evidence you would need.
  2. Clarify what is being asked and what a complete answer would contain.
  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?

Decompose risk-adjusted cost per member into owned leaf metrics

Hard · metric tree · price volume mix · coding intensity · ownership

Build a metric tree, at most four levels deep, from risk-adjusted allowed PMPM down to leaves an owner can move. Data: medical_claim_line (allowed_amount, units, procedure_code, place_of_service_code, service_start_date, claim_version, frequency_code), pharmacy_claim (allowed_amount, days_supply, is_generic, formulary_tier, reversal_flag), member_enrollment (coverage spans, prospective_risk_score). Give the arithmetic identity each split rests on, the leading indicator at each leaf, and identify the one node where the arithmetic is exact but the attribution is not.

Approach

  1. State the base identity before drawing anything. Allowed PMPM equals total allowed over member-months, and it decomposes exactly by service category c as the sum over c of (units_c / member-months) times (allowed_c / units_c). Utilization per member-month and allowed per unit, summed across categories, so category mix is inside the sum rather than a separate hand-wave.
  2. Give the change decomposition too, because the tree will be read on deltas: the change in PMPM equals the sum over categories of (change in utilization times base price) plus (base utilization times change in price) plus (change in utilization times change in price). The third term is the interaction, it is not noise, and an analysis that drops it will not reconcile.
  3. Build the medical branch to leaves with owners: inpatient admits per 1,000 member-months and allowed per admit (with DRG case mix as the sub-split), ambulatory visits per 1,000 and allowed per visit split by place_of_service_code, and emergency visits per 1,000 and allowed per visit. Prepare the data with version dedup to the surviving claim_version before a single dollar is summed, since frequency_code 7 replaces and 8 voids.
  4. Build the pharmacy branch on 30-day equivalents: scripts_30 equals the sum of days_supply over 30 on unreversed fills, so pharmacy PMPM equals (scripts_30 per member-month) times (allowed per 30-day script). Split the price term exactly as g times the generic price plus (1 minus g) times the brand price, where g is the generic dispensing rate, which makes generic substitution and unit price separable leaves with different owners.
  5. Attach one leading indicator per leaf: prior-authorization approvals and elective surgical bookings ahead of inpatient admits, contract effective dates ahead of allowed per unit, site-of-service steering ahead of the ambulatory place_of_service mix, new-to-brand starts and formulary tier placement ahead of pharmacy price.
  6. Name the node where arithmetic is exact but attribution is not: the risk-adjustment denominator. Dividing by the population mean prospective_risk_score is exact arithmetic, but the score is built from coded diagnoses, so more complete coding raises the denominator and lowers risk-adjusted PMPM with no change in care delivered. Carry raw PMPM, the mean risk score trend and a coding-intensity measure such as diagnoses per member-year beside it, permanently.

Worked solution (45 min)

  1. Write the base identity and the three-term change decomposition on paper first, and confirm the terms sum to the total change on a two-category toy example before touching real data.
  2. Specify the preparation rules that precede any aggregation: dedup medical_claim_line to the surviving version per claim_id using claim_version and frequency_code, drop both rows of every reversed pharmacy pair, and build member-months from coverage spans with partial months counted fractionally.
  3. Draw the medical branch and the pharmacy branch to leaf level, writing the identity beneath each split rather than only the metric name.
  4. Write the generic-dispensing split as the exact price identity and confirm it reproduces the observed allowed per 30-day script.
  5. Attach one leading indicator and one named owning function to each leaf.
  6. Write the caveat on the risk-adjustment node, including the two companion series that must be published with it.

Expected result: A four-level tree rooted at risk-adjusted allowed PMPM, splitting by service category into utilization per member-month and allowed per unit, with an inpatient sub-split on DRG case mix, an ambulatory sub-split on place_of_service_code, and a pharmacy branch on 30-day equivalents whose price term is split exactly by generic dispensing rate; each leaf carries a named owner and a leading indicator; and the risk-adjustment denominator is flagged as exact arithmetic with unreliable attribution, published alongside raw PMPM, the mean risk score trend and a coding-intensity series.

Verify it yourself

  • Reconcile the leaves back to the root: the summed category contributions must equal total allowed PMPM to within rounding, and the three change terms must sum to the observed period change.
  • Recompute total allowed with and without version dedup. Any gap is the double-counted adjusted claims the tree would otherwise attribute to real utilization.
  • Verify the pharmacy price identity numerically: generic dispensing rate times generic price plus its complement times brand price should reproduce the observed blended allowed per 30-day script.
  • Hold care constant and simulate a 5 percent rise in mean prospective_risk_score. Risk-adjusted PMPM should fall by roughly the same proportion, which is the attribution problem made visible.

Follow-up

  • Utilization is flat and allowed per unit is flat, yet PMPM rose 4 percent. Name every place the increase can be hiding.
  • Your member-month denominator came from coverage spans that overlap across products for some members. What does that do to PMPM, and how do you decide whether to deduplicate?
  • Which leaf would you refuse to put on a team's scorecard, and why?

First-pass denial rate doubled in one received week

Medium · pipeline failure · segment cuts · denominator definition

First-pass denial rate jumped from 6.1 to 11.8 percent in a single received_date week and stayed at the new level. Nothing in the adjudication rules changed that week. You have medical_claim_line: claim_id, claim_version, frequency_code, claim_status, denial_reason_code, member_id, received_date, adjudicated_at, billing_provider_npi. The metric counts lines whose first adjudication returns 'denied', over lines received in the window at claim_version = 1. Find the cause, say whether denial behaviour actually changed, and deliver the corrected series plus the query change that fixes it.

Approach

  1. Cut the excess by denial_reason_code before anything else. A behaviour change spreads across codes; an upstream failure concentrates in one. If a single eligibility-related code carries nearly all of the 5.7 point excess, the claims are fine and the eligibility data was not.
  2. Join the denied lines to member_enrollment and compare the span's created_at to the claim's received_date. Lines denied for members whose coverage span loaded after the claim arrived are a load-ordering failure, not a coding failure.
  3. Check resolution downstream: take those claim_ids and look for a later version with frequency_code 7 that adjudicates to 'paid'. A high resubmit-and-pay share confirms the denial was transient and recoverable.
  4. Verify the denominator is not the mover. Count lines at claim_version = 1 by received_date and check the weekday mix, because submission batching makes received_date strongly day-of-week patterned and a short or holiday week shifts the denominator without changing behaviour.
  5. Confirm runout: the metric should be held until 60 days of adjudication have passed, so check that the comparison weeks are equally mature rather than comparing a settled week to a fresh one.
  6. Restate the series with the affected reason code broken out as its own line, and change the query to carry denial_reason_code into the reported breakdown rather than only the headline rate.

Follow-up

  • The affected lines all get paid on resubmission. Is the first-pass denial rate then wrong, or right and uninteresting?
  • How would you monitor for this class of failure without waiting for someone to notice a chart?
  • What changes if the excess is spread evenly across denial_reason_code instead of concentrated?

Suggested practice checklist

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

Day 1 — Fix the scope and set a baseline

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

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

Day 2 — One query pattern, written three times

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

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

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

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

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

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

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

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

Day 5 — Your own work, timed

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

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

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

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

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

Day 7 — Taper

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

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

Ambiguous requests are the test

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

Imagine you are given conflicting results from two models. How would you investigate?

Medium · behavioural and stakeholder questions

Approach

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

Follow-up

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

Tell us about a successful project you led. What was your role?

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

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

What motivates you 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

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