Interview guides · healthcare AI
healthcare AI Data Scientist Interview Questions & Guide 2026
A two-week prep plan for healthcare AI data scientist candidates: write your answer before reading the solution, revisit misses three days later.
The 60-second brief
As a Data Scientist at healthcare AI, you are at the intersection of complex clinical data and cutting-edge machine learning. Your work directly influences how the company processes health information, optimizes patient outcomes, and scales technical solutions. You will be responsible for transforming raw, often messy, healthcare datasets into actionable insights that power the company's core products and internal decision-making processes.
SQL is seldom the hardest round and is often the one that eliminates people. The working bar is usually window functions, correct deduplication, and joins that do not silently fan out rows, rather than obscure syntax.
Focus areas
- Build member-month denominators from overlapping coverage spans
- Reconstruct drug exposure intervals from dispensing records
- Minimise protected health information in every extract
Overview
This role is both technically demanding and highly collaborative. You will engage with product managers, engineers, and clinical experts to define metrics, build predictive models, and solve ambiguous problems in a fast-paced environment. Success requires not only a high level of proficiency in statistical analysis and coding but also the ability to communicate technical findings to stakeholders who may not have a data background. You are expected to be a self-starter who can navigate the complexities of the healthcare domain while maintaining high standards for accuracy and ethical AI development.
The healthcare AI interview process
healthcare AI candidates report 3 rounds · ≈ 3-5 weeks. The stages below are what candidates describe, not a published process.
Application Review
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
Online Assessment
A handful of shapes account for most of what gets asked in this format: a ranking or deduplication inside groups, a running or rolling total, a period-over-period comparison, and a cohort tracked forward over time. Recognising the shape quickly is most of the speed here; deriving it from scratch while a clock runs is where the time goes. Know that a window function keeps every row while a GROUP BY collapses them, and know which one the question needs. If the exercise is in Python instead of SQL, the same shapes arrive as groupby with transform, shift and merge, and the same grain mistakes are available.
What to demonstrate
- Whether you reach the right construct without a detour, such as ROW_NUMBER over a partition to deduplicate instead of a self-join against a MAX subquery
- Whether you know what your window frame actually is, since adding ORDER BY inside OVER changes the default frame and silently changes a running total
- Whether the thing runs. A near-miss that throws an error scores below a plainer query that returns the right rows.
How to prepare
- Write each of the four shapes once from memory against a small schema and keep the working version somewhere you will reread it: dedupe with ROW_NUMBER, a running total, a month-over-month change with LAG, and a retention table
- Compute one running total twice on data with tied timestamps, once on the default frame and once with ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, and look at where the two disagree
- If Python is on the table, rebuild the dedupe and the running total with groupby and cumsum, then assert the two implementations return identical rows
Background Interviews
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
Pre-post evaluation on a high-cost or high-risk cohort
Cohorts selected on an extreme value of the outcome regress toward the mean on their own. Members identified as the top 1 percent of spend in one year spend far less the next, whether or not anyone intervenes, because the selecting year captured both chronic severity and one-off events. A pre-post design on such a cohort will report savings every time. A concurrent comparison group selected by the same rule in the same period, or a regression discontinuity at the selection threshold, is the minimum credible design.
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.
Reaching for a model before the target metric exists
Before naming an algorithm, write down the label, the prediction time, and the action that changes when the score crosses a threshold. If you cannot say what decision the output drives, any modelling choice is guesswork dressed up as method.
Comparing periods without accounting for seasonality or day-of-week
Compare whole weeks against whole weeks and check whether the same swing appeared in prior cycles or prior years before attributing it to anything you changed. Weekday and weekend populations often differ enough that a Tuesday-to-Saturday comparison is meaningless.
Questions & practice
Explain the trade-offs between different machine learning models for a classification task.
Medium · machine learning and modelling
Approach
- Set a baseline first, so any model has something honest to beat.
- Say how the offline result would be validated online before it is trusted.
- Pick an evaluation metric that matches the cost of each error type, not a default.
Follow-up
- What would you monitor after launch to know the model is still valid?
- Where could label leakage enter this setup?
Build a claims lag triangle and complete recent months
Medium · chain ladder · runout · pivot
medical_claim_line has claim_id, claim_version, frequency_code, service_start_date, paid_date, allowed_amount, claim_status. Using 24 fully mature incurred months, build a development triangle of allowed dollars by incurred month and payment lag in whole months, derive cumulative completion factors by chain ladder, then estimate ultimate allowed for the three most recent incurred months at a stated paid-through date. Deduplicate to surviving claim versions before building the triangle. Return incurred_month, paid_to_date, completion_factor, estimated_ultimate.
Approach
- Deduplicate to surviving claim versions and keep paid lines first. A triangle built on all versions develops on adjustment churn rather than on payment timing, and replacements arrive late, so the distortion concentrates in exactly the tail you are trying to estimate.
- Compute lag as a whole-month difference between incurred month and paid month, not as day difference divided by 30. Ragged month lengths otherwise shuffle identical claims between lag buckets depending on which month they fall in.
- Pivot to incurred_month by lag, cumulate along lag, then form age-to-age factors as the ratio of the column L+1 total to the column L total, summed over incurred months mature enough to have both. Volume weighting is the chain ladder; a simple mean of per-month ratios lets one low-volume month dominate the factor.
- Chain the age-to-age factors from each lag to ultimate and invert: completion factor at lag L is the reciprocal of the product of factors from L onward. Apply as estimated_ultimate = paid_to_date / completion_factor.
- State the assumption you have just made, which is that the development pattern is stable. It is not, after a claims-system migration, a network change or a processing backlog, and the most recent month's factor is the least reliable because it rests on the fewest observations while carrying the largest adjustment.
Worked solution (35 min)
- Deduplicate to surviving versions, drop voids, keep claim_status 'paid', and derive incurred_month from service_start_date and paid_month from paid_date.
- lag = (paid_month.year - incurred_month.year) x 12 + (paid_month.month - incurred_month.month); drop negative lags and investigate them separately.
- Pivot to a triangle of summed allowed_amount, cumulate along the lag axis, and mask cells past the paid-through date so no cell contains a future payment.
- Compute volume-weighted age-to-age factors per lag over the mature rows, then chain them into cumulative completion factors.
- Apply the factor for each recent month's current maturity to its paid_to_date and return the four columns.
Expected result: Three rows. Completion is well below 1 at short lag and approaches 1 in the tail; for a mixed medical book a one-month-old incurred month commonly sits far from complete, while a twelve-month-old one is close. Exact values are book-specific, so the reviewable property is monotonicity and the holdout test below, not the numbers themselves.
Verify it yourself
- Cumulative completion factors are non-decreasing in lag and converge toward 1 at the tail.
- Hold out one fully mature incurred month, apply the factors at each of its intermediate maturities, and confirm each estimate lands within a few percent of its known total.
- estimated_ultimate is greater than or equal to paid_to_date for every row.
- A pharmacy-only triangle completes far faster than an inpatient-facility-only triangle, which confirms the lag computation is reading real payment timing.
Follow-up
- A processing backlog means the last two months developed slower than history. What does your estimate do, and how would you detect that before reporting?
- Pharmacy, professional and inpatient facility develop on different clocks. How do you split the triangle, and what breaks if the service mix shifts?
- What happens to a PMPM series if someone reports an unadjusted recent month, and in which direction does the error point?
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
- 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.
- 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.
- 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.
- 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.
- Restrict service_start_date to the month boundaries, then groupby member_id and sum. Sort descending and return.
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?
Find inpatient encounters with no resulted lab during the stay
Medium · anti-join · null semantics · event matching
encounter holds encounter_id, patient_id, encounter_type, admit_ts, discharge_ts and facility_id. lab_result holds result_id, order_id, patient_id, encounter_id (NULL for outpatient standing orders), loinc_code, specimen_collected_ts, resulted_ts and result_status. Return every inpatient encounter discharged in 2025 with no final or corrected lab_result linked to it. A colleague wrote WHERE encounter_id NOT IN (SELECT encounter_id FROM lab_result) and got zero rows back. Say why, write the correct query, then say what changes when labs must instead be matched on patient_id with the specimen collected between admit_ts and discharge_ts.
Approach
- Name the mechanism rather than the symptom. x NOT IN (subquery) expands to x <> y1 AND x <> y2 AND ..., and a single NULL y makes that chain UNKNOWN, never TRUE. Since lab_result.encounter_id is nullable by design for standing orders, this query can only ever return zero rows.
- Rewrite as NOT EXISTS, or LEFT JOIN with an IS NULL filter. Both treat a NULL key as no match rather than as unknown. Adding IS NOT NULL inside the NOT IN subquery also works, but NOT EXISTS is the habit that survives someone making another column nullable later.
- Put the result_status predicate inside the correlated subquery or the ON clause, not in an outer WHERE. Outside, it turns the anti-join back into an inner join and an encounter whose only labs were cancelled disappears instead of qualifying.
- For the timestamp variant, match on patient_id with specimen_collected_ts inside the stay rather than resulted_ts. A specimen drawn an hour before discharge can result the next day, and anchoring on resulted_ts would wrongly call that stay lab-free.
- Restrict to encounter_type 'inpatient' and discharge_ts in 2025, and report open encounters with a NULL discharge_ts as a separate count instead of letting the filter swallow them.
Follow-up
- Write the LEFT JOIN form and say exactly where the result_status predicate must sit for the two forms to agree.
- How would you separate encounters whose only labs were cancelled from encounters with no lab rows at all?
- Some encounters carry member_id NULL because the person index did not match. What does that do to a payer-side version of this measure?
Reconstruct drug coverage intervals and compute proportion of days covered
Hard · gaps and islands · window functions · adherence
pharmacy_claim holds fill_id, member_id, ndc_code, therapeutic_class_code, fill_date, days_supply, reversal_flag and reversed_fill_id. Early refills overlap, so days_supply must be laid end to end: each fill's coverage starts at the later of its fill_date and the previous interval's end. Both rows of a reversed pair are excluded. For one therapeutic_class_code over 2025-01-01 to 2025-06-30, return per member the proportion of days covered, defined as covered days divided by days from first fill_date to window end, plus the share of members at or above 0.80. Require at least two fills and 91 days of follow-up.
Approach
- Clean the fills first. Drop rows with reversal_flag TRUE and also the fills they point at through reversed_fill_id. Dropping only the reversal row leaves an original fill counted as exposure that never reached the member. Use NOT EXISTS for that second step, since reversed_fill_id is nullable and NOT IN would return nothing.
- Shift, never stack. The shifted end is covered_end_i = GREATEST(fill_date_i, covered_end_{i-1}) + days_supply_i, which looks recursive but has a closed form: with cum_i the running sum of days_supply through fill i, covered_end_i = cum_i + MAX over j <= i of (fill_date_j - cum_{j-1}). That is SUM(days_supply) OVER (ORDER BY fill_date ROWS UNBOUNDED PRECEDING) plus a running MAX of an anchor column, so it is two window functions and no recursive CTE.
- Derive covered_start_i as GREATEST(fill_date_i, LAG(covered_end)). The intervals are disjoint by construction, so covered days is a plain sum of lengths and never needs a distinct day grid.
- Clip intervals to the window end before summing, and decide explicitly whether to clip at disenrollment as well. Supply that runs past the window must not inflate the numerator.
- Use the denominator the spec names, first fill_date to window end, and hold it constant across classes. A fixed-window denominator yields a different and usually lower number, and mixing the two across classes makes the comparison meaningless.
- Apply the inclusion rules at member level after the intervals are built, then compute the share at or above 0.80 with the qualifying member count beside it.
Worked solution (40 min)
- Filter to the therapeutic_class_code and window, then remove reversal rows and their originals with NOT EXISTS.
- Per member ordered by fill_date, compute cum_supply and anchor = fill_date - (cum_supply - days_supply), then covered_end = cum_supply + MAX(anchor) OVER (ORDER BY fill_date ROWS UNBOUNDED PRECEDING).
- Compute covered_start = GREATEST(fill_date, LAG(covered_end) OVER (ORDER BY fill_date)), clip both ends to the window, and drop intervals that collapse.
- Sum interval lengths as covered_days, compute follow_up_days from first fill_date to window end, and divide.
- Apply the two-fill and 91-day rules, then aggregate the share at or above 0.80.
Expected result: One row per qualifying member with covered_days, follow_up_days and pdc in [0, 1], plus a summary row with qualifying members and the share at or above 0.80. A member with 30-day fills on 2025-01-01, 2025-01-20 and 2025-04-01 is covered 2025-01-01 to 2025-03-01 and 2025-04-01 to 2025-04-30, giving 60 + 30 = 90 covered days over 181 follow-up days and a PDC of 0.497.
Verify it yourself
- No pdc exceeds 1.0 before any clipping. A value above 1 proves supplies were stacked instead of shifted.
- On a twenty-member sample, the summed interval lengths equal the distinct covered day count from a slow day-grid version.
- A member with one fill is excluded by the two-fill rule rather than appearing with a PDC of 1.0.
- Re-running with reversals left in raises covered days for exactly the members who have a reversed_fill_id, and for no one else.
Follow-up
- A member is hospitalised for twelve days mid-window, when the facility supplies medication. Should those days count as covered, and what do published adherence measures do about them?
- Someone wants to classify adherence over twelve months and then compare mortality from month zero. What is wrong with that design and what fixes it?
- Two different ndc_codes in the same therapeutic class overlap. Is that stacking or switching, and how does your interval logic treat each case?
How would you measure the success of a new feature rollout?
Medium · product sense and metrics
Approach
- Decompose the metric into the rates that drive it, and say which one you would check first.
- State what result would change your recommendation, so the answer is falsifiable.
- 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?
Given a specific business challenge, how would you design an experiment to validate your hypothesis?
Medium · a/b testing and experimentation
Approach
- State the primary metric and the minimum effect worth shipping, then size the test.
- Say whether units interfere with each other, and switch design if they do.
- Name the guardrails that would stop a launch even on a positive primary result.
Follow-up
- How would you handle interference between treated and control units?
- What would you conclude if the result is positive but the test is underpowered?
Walk me through how you would approach a data-heavy task with limited documentation.
Medium
Approach
- Say what you would check first and why it is the highest-information step.
- State your assumptions explicitly before working the problem.
- Clarify what is being asked and what a complete answer would contain.
Follow-up
- How would you know your answer was wrong?
- What assumption would you test first?
How do you ensure your models remain robust when deployed in a live production environment?
Medium
Approach
- State your assumptions explicitly before working the problem.
- Clarify what is being asked and what a complete answer would contain.
- Say what you would check first and why it is the highest-information step.
Follow-up
- How would you know your answer was wrong?
- What assumption would you test first?
Redesign an adherence metric an outreach team cannot quietly inflate
Medium · gaming · adherence · denominator design · threshold bunching
An outreach team is paid on the share of members reaching proportion of days covered of 0.80 or higher in a therapeutic class, computed from pharmacy_claim (member_id, therapeutic_class_code, fill_date, days_supply, refill_number, reversal_flag, reversed_fill_id). The denominator is members with at least two fills in the class and at least 91 days of follow-up, over a 12-month window. Name three ways the team raises this number without any member taking more medication, then redesign the metric and its guardrails so each lever is closed or visible.
Approach
- Attack the denominator first, because it is the cheapest lever. A member who fills once and abandons never enters the denominator at all, so the worst outcome in the class is invisible, and any effort spent on first-fill abandonment lowers the reported share by moving those members in. The incentive runs backwards.
- Attack the window arithmetic second. With the denominator running from first fill to window end, a member whose first fill lands late in the year has a short denominator that is trivially easy to cover, so steering new starts to the last quarter raises the metric mechanically. Report by index quarter or fix the window and require the index fill in the first quarter.
- Attack the threshold third. Days of supply dispensed late in the window count only up to the window end, but a fill placed 60 days before close, on a member whose last on-hand day has already passed, adds up to 60 covered days, about 0.16 of a 365-day denominator. That alone moves a member from 0.77 to 0.93 with no change in what anyone swallows.
- Close the dispensing-side hole: a fill that is billed and reversed is not exposure. Exclude both rows of a reversed pair via reversal_flag and reversed_fill_id, and collapse overlapping fills by pushing each interval start to the later of fill_date and the prior interval's end, so early refills shift coverage forward rather than stacking.
- Redesign the scorecard as a pair rather than a single number: the threshold share stays as the headline, and mean PDC plus the share at 0.90 or higher travel with it, because a distribution cannot be bunched at a threshold without showing it.
- Add the guardrails that make each lever visible: first-fill abandonment rate (fills with refill_number 0 never followed by a second fill, plus reversed first fills), the share of covered days originating from fills in the final 60 days of the window, and the distribution of PDC in the bands just below and just above 0.80.
Worked solution (30 min)
- Write the exposure-interval construction explicitly: drop reversed pairs, sort fills per member and class by fill_date, set each interval start to the greater of fill_date and the prior interval end, and truncate the final interval at the window end.
- Write the denominator in two variants, the incumbent at-least-two-fills rule and an index-fill rule requiring the first fill in the first quarter with at least 273 days of follow-up, and state what each includes that the other does not.
- Enumerate the three gaming levers with the arithmetic that makes each one work, including the 60-day end-of-window fill computed against a 365-day denominator.
- Specify the headline metric plus the two companions (mean PDC, share at 0.90 or higher) and the three guardrails, each with numerator, denominator and window.
- Write one sentence stating that dispensing is a proxy for taking and that the proxy overstates adherence in the direction of anyone who fills and does not take.
Expected result: A redesign in which: reversed fills are excluded and overlaps shift forward rather than stack; the denominator is anchored on an index fill in a fixed window so late starters cannot buy a short denominator; the threshold share is reported with mean PDC and the share at 0.90 or higher; and three guardrails ship with it, namely first-fill abandonment rate, the share of covered days contributed by fills in the last 60 days of the window, and the PDC distribution in the bands immediately below and above 0.80.
Verify it yourself
- Hand-compute PDC for a member with fills on day 1, day 25 and day 200 at 30 days supply each in a 365-day window. Overlapping the day-25 fill forward gives 90 covered days and PDC of about 0.25; stacking incorrectly gives 90 days too but misplaces them, so check the interval endpoints, not just the total.
- Compare the member count under both denominator rules. The index-fill rule should be strictly smaller or equal on early starters and should pull in first-fill abandoners the incumbent rule excluded.
- Plot the PDC histogram around 0.80. A smooth distribution is consistent with real behaviour; a spike in the first band above the threshold is not.
- Sum covered days sourced from fills in the final 60 days of the window across members who cross the threshold. A large share concentrated there is the end-of-window blitz showing up directly.
Follow-up
- The share at 0.80 or higher rose four points and mean PDC rose 0.4 points. What is your reading, and what do you look at next?
- Would you pay on 0.80 at all, or on the continuous measure? Say what each choice costs you.
- Possession is not ingestion. Name a measurable consequence in another table that would corroborate a real adherence improvement, and state its own weakness.
Adherence share collapsed the month a feed was added
Easy · pdc · interval sql · identity resolution
The share of members with proportion of days covered at or above 0.80 in one therapeutic class fell from 0.71 to 0.58 in a single month. pharmacy_claim carries fill_id, member_id, ndc_code, therapeutic_class_code, fill_date, days_supply, quantity_dispensed, refill_number, reversal_flag, reversed_fill_id and source_system_code. There is no person-level key above member_id and no enrollment table on hand, so every diagnostic has to run on pharmacy_claim alone. That month the pipeline began ingesting a second pharmacy source. Determine whether adherence actually changed, and hand back a PDC query you would defend line by line.
Approach
- Compute controls that depend on neither member identity nor the PDC code: total fills in the class per month, and total days_supply dispensed in the class per month. Both are sums over rows, so neither moves when one person's fills split across two member_ids, which is exactly what a per-member control cannot promise. If both are flat while PDC falls, no dispensing behaviour changed and the computation or the keys did.
- Check days_supply for nulls and zeros by source_system_code. If the new source omits days_supply and the code coalesces null to zero, covered days vanish and PDC falls even though the fills are there.
- Check for member identity splitting using the columns you actually have. There is no person key above member_id, so the split has to be found by its footprint: distinct member_id in the class jumping at the break while total fills stay flat, and a rise in the share of member_ids whose earliest fill for a given ndc_code carries refill_number above zero, which is a continuation history that lost its beginning. When one person is split, each id may fall below the two-fill denominator requirement and drop out, and the ids that do survive carry artificial gaps.
- Check reversals. A reversed fill is two rows, the fill and a row with reversal_flag TRUE pointing at reversed_fill_id, and both must be excluded from exposure. If the new source expresses reversals differently and reversed_fill_id does not link, phantom coverage appears, which pushes PDC up rather than down, so use this to rule the cause in or out.
- Verify the denominator and window are unchanged: members with at least two fills in the class and at least 91 days of follow-up, over a stated fixed 12-month window, never a mixture of window lengths.
- Write the PDC query so overlapping refills shift the next interval's start to the later of fill_date and the prior interval's end, so a day is covered at most once, and cap at one day per calendar day.
Follow-up
- Why is PDC preferred to medication possession ratio when early refills are common?
- You want to compare adherent and non-adherent members on hospitalisation. What is wrong with classifying on a 12-month PDC and then following from day zero?
- A member switches to a different drug in the same class mid-year. How does your interval logic handle that, and is the class the right grain?
Suggested practice checklist
Instead of guessing where the week should go, day one measures it under a fixed rubric and allocates the remaining hours in proportion to the gaps. The method is deliberately rigid: the allocation is written down before any studying starts and is not renegotiated when a topic turns out to be unpleasant.
Day 1 — Diagnostic, scored before you study anything
- Sit a 100-minute timed diagnostic in four blocks: 30 minutes of SQL across three prompts, 25 minutes of short-answer statistics, 25 minutes on one modelling or case prompt, and 20 minutes delivering one behavioural story aloud.
- Score each block from 0 to 3 on a fixed rubric where 3 is correct and fluent, 2 is correct but slow or prompted, 1 is partially correct, and 0 is stuck, grading the output rather than how the attempt felt.
- Allocate the hours for days two to five roughly in proportion to 3 minus the score in each block, write the allocation down, and commit to not revising it midweek.
Deliverable: A scored rubric and a fixed hour allocation for the rest of the week.
Day 2 — Largest gap: find the boundary rather than the subject
- Break the weakest area into five named sub-skills (for query work: grain control, window frames, date arithmetic, set logic with NULLs, and reading a query plan) and rate each one, so the rest of the week targets a sub-skill instead of a subject.
- Solve three problems chosen to sit just above where the rating drops off, and for each write the first move you failed to make.
- Re-solve one of them from memory four hours later, on paper, with nothing open.
Deliverable: A five-item sub-skill map with the two blocking sub-skills circled.
Day 3 — Largest gap: drill the blocking sub-skill
- Do eight short repetitions of the same shape rather than eight different problems, so what you practise is the pattern and not the puzzle.
- Write the rule you now hold in one sentence, then test it against a case built to break it: a ranking function over a column with ties, or a two-sample test on observations that are obviously dependent.
- Have someone else read your one-sentence rule and find the precondition you left out.
Deliverable: One rule statement with its preconditions attached and one counterexample that would have caught the incomplete version.
Day 4 — Second gap, plus maintenance on your strongest area
- Run the same sub-skill map and boundary protocol on the second-largest gap, compressed into half the day.
- Spend 25 timed minutes on your strongest area to stop it decaying, choosing the hardest problem you can still finish rather than an easy warm-up.
- Compare how the two areas fail: whether you lose time on recall, on setup, or on arithmetic, because the fix differs for each.
Deliverable: A second sub-skill map plus a one-line diagnosis of how each area fails you.
Day 5 — The gap that is not a skill
- Record yourself answering one technical and one behavioural prompt, then count two things in the playback: how many seconds before your first clarifying question, and how many sentences you started without knowing where they ended.
- Rewrite your three most-used stock phrases into shorter versions, and practise saying "I do not know, here is how I would find out" without softening it into a guess.
- Deliver one answer again with a hard 90-second limit to force structure before detail.
Deliverable: Two recordings with a counted improvement in time-to-first-question.
Day 6 — Retest under day-one conditions
- Sit the same 100-minute diagnostic structure with new prompts of comparable difficulty and score it on the identical rubric.
- Compare block by block, and for any block that did not move, change the method rather than adding hours: a block stuck at 1 usually means the practice was too varied, not too short.
- Write which single block you would still lose the offer on.
Deliverable: A second scored rubric placed next to the first, with one named remaining risk.
Day 7 — Full loop under interview conditions
- Run a 60-minute mock covering the two blocks that moved least, with an interviewer instructed to interrupt and change direction.
- Write your recovery script for the moment you go blank: restate the question, state your assumption, name the first thing you would check.
- Reduce the week to the rule statements you wrote, each with its preconditions attached, then say every one of them out loud without reading it and cut any you cannot state in a single sentence, since a rule you have to reconstruct mid-answer will not survive being interrupted.
Deliverable: A one-page card holding the recovery script and only the rules you could state from memory.
Stories where someone disagreed with you
Have two ready. In one, the data was on your side and you had to move someone who outranked you. In the other, the pushback was correct and you changed position. The second is the harder story and it lands better, because it shows you separate being right from being attached to an answer. Name the person's actual objection.
How do you prioritize competing data requests from different stakeholders?
Medium · behavioural and stakeholder questions
Approach
- Name the disagreement or constraint, and how you resolved it with evidence.
- Pick a story where you drove the decision, not one where you observed it.
- Quantify the outcome, including what you would not claim credit for.
Follow-up
- How did you know the outcome was caused by your change?
- What did you decide not to do, and why?
Tell me about a time you had to explain a complex technical result to a non-technical stakeholder.
Medium · behavioural and stakeholder questions
Approach
- Close with what you would do differently, concretely.
- State the situation in two sentences and spend the rest on your reasoning.
- 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?
How do you handle missing or noisy data in a healthcare context?
Medium · behavioural and stakeholder questions
Approach
- Name the disagreement or constraint, and how you resolved it with evidence.
- Quantify the outcome, including what you would not claim credit for.
- Close with what you would do differently, concretely.
Follow-up
- What would you do differently if you ran that project again?
- What did you decide not to do, and why?