Interview guides · DataAnnotation
DataAnnotation Data Scientist Interview Questions & Guide 2026
Data scientist interview prep for DataAnnotation: original practice on experiment design, SQL and metric reasoning, with worked solutions.
The 60-second brief
As a Data Scientist - AI Trainer at DataAnnotation, you are at the forefront of shaping the next generation of artificial intelligence. This role is not merely about analyzing historical data; it is about actively training, refining, and evaluating the reasoning capabilities of large-scale models. You act as a bridge between complex human intelligence and machine learning outputs, ensuring that DataAnnotation's AI products are accurate, safe, and highly performant.
Ask early whether the loop includes an asynchronous take-home or a timed live case, because the two are graded on different things. A take-home is read as an artifact: the question you decided to answer, what you did about missing or malformed records, and a conclusion stated plainly enough for someone to act on. A reviewer who cannot rerun your notebook discounts the result whatever score is printed in it. Hold to the stated time box and write down what you would have done with more of it, since the follow-up round is usually a live defence of the same work.
Focus areas
- Decompose expected loss into PD, LGD, EAD
- Set fraud thresholds by expected cost
- Read vintage curves, not blended portfolio averages
Overview
The impact of this role is direct and measurable. You will be responsible for creating high-quality training data, auditing model responses for logical consistency, and developing nuanced evaluation frameworks that define what "success" looks like for DataAnnotation's models. Because DataAnnotation's work spans diverse domains—from clinical research and biostatistics to marketing analytics and complex decision science—your contributions directly influence the reliability of AI tools used by users globally.
This position is ideal for professionals who thrive on intellectual rigor and enjoy the challenge of solving ambiguous problems. You will work in a fast-paced, highly autonomous environment where your ability to decompose complex tasks into clear, actionable data instructions is paramount. Success here requires a blend of technical expertise, critical thinking, and the ability to articulate complex reasoning clearly.
The DataAnnotation interview process
DataAnnotation candidates report 4 rounds · ≈ 3-5 weeks. The stages below are what candidates describe, not a published process.
Initial Assessment
Much of what gets scored here happens out loud while you type. Nobody can see your reasoning inside a half-written query, so five silent minutes read as being stuck even when they are not. State the plan in plain language first: which tables, what grain you are aggregating to, and the one filter that defines the population. Then write it. The narration doubles as insurance, because a wrong plan gets caught early and cheaply while a wrong query gets caught at the end with no time left to redo it. A timed statistics section, where one exists, is a separate test with its own clock.
What to demonstrate
- Whether the query you write matches the plan you just described
- What you do with a hint, meaning whether the correction gets absorbed or the first approach gets defended
- Whether you can debug your own wrong output by reading the result set and naming which part of the query produced the anomaly
How to prepare
- Solve three problems while screen-sharing into a recording, then watch it back and mark every stretch longer than thirty seconds where you said nothing
- Practise compressing the plan into one sentence before typing, then check afterwards whether the finished query actually matched it
- Time yourself on statistics questions that carry a business reading, such as what a confidence interval does and does not claim, rather than re-reading notes without a clock
Complex Task Evaluation
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
Scenario Presentation
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.
Continuous Evaluation
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
Where candidates lose points
Reading the most recent months of fraud and dispute rates as final
Consumer dispute rights commonly run around 120 days from the transaction or expected delivery date, and several reason codes run considerably longer, so the disputes belonging to a recent transaction month have simply not been filed yet. Any chart attributed by transaction date therefore slopes down at the right edge regardless of what is happening. The fix is to report only matured cohorts, or to apply development factors estimated from completed months and to show the estimate as an estimate.
Assuming a model is fair because protected attributes are not among its inputs
Postcode, device, tenure, income proxies and even transaction patterns correlate with protected characteristics, so a model can produce a disparate outcome without ever reading the attribute. Credit decisions additionally carry an explainability obligation in many jurisdictions, since a denial has to be accompanied by its principal reasons, which constrains model form and feature engineering rather than being a reporting afterthought. Treating fairness testing and reason-code generation as design constraints from the first model version is far cheaper than retrofitting them to a deployed one.
Generalising beyond the population the sample actually supports
State the frame the sample was drawn from and where it diverges from the population you want to talk about: time window, platform, geography, opt-in. If a group is excluded from the frame, either weight to known margins or narrow the claim rather than quietly extending it.
Explaining an aggregate move without decomposing the mix shift
Split the change in the aggregate into within-segment movement and movement in segment weights before you explain it. Every segment's rate can fall while the overall rate rises, purely because volume shifted toward segments that already had higher rates.
Questions & practice
Given a prompt that requires multi-step reasoning, what specific indicators do you look for to determine if the model is hallucinating?
Medium · machine learning and modelling
Approach
- Frame the prediction: the label, the moment of prediction, and the action it triggers.
- Check what information would not exist at prediction time, and exclude it.
- 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?
- How would you choose the decision threshold, and who owns that choice?
How do you balance being concise with being comprehensive when training a model for specialized user queries?
Medium · machine learning and modelling
Approach
- 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.
- 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?
- How would you choose the decision threshold, and who owns that choice?
If a model provides a statistically sound but contextually irrelevant answer, how do you guide it toward better alignment?
Medium · machine learning and modelling
Approach
- Frame the prediction: the label, the moment of prediction, and the action it triggers.
- 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
- Where could label leakage enter this setup?
- How would you choose the decision threshold, and who owns that choice?
How do you ensure that a model remains neutral and objective when answering controversial or subjective questions?
Medium · machine learning and modelling
Approach
- Check what information would not exist at prediction time, and exclude it.
- Set a baseline first, so any model has something honest to beat.
- Pick an evaluation metric that matches the cost of each error type, not a default.
Follow-up
- How would you choose the decision threshold, and who owns that choice?
- What would you monitor after launch to know the model is still valid?
Build a vintage delinquency table without pivot or unstack
Easy · vintage analysis · cohorts · groupby · cumulative max
fct_loan_performance_monthly gives loan_id, origination_month, months_on_book, days_past_due, charge_off_flag and restructured_flag. Produce a DataFrame with one row per origination_month and columns for months_on_book 0 through 12, each cell holding the share of that vintage's funded loans that had ever reached 90 or more days past due, or charge-off, by that age. You may not use pivot, pivot_table, crosstab or unstack. Cells for ages a cohort has not yet reached must be NaN rather than zero.
Approach
- Define the per-row indicator as days_past_due >= 90 or charge_off_flag, then take a cumulative maximum of it per loan ordered by months_on_book, because the metric is reached-by-age-m, not in-that-state-at-age-m.
- Deal with restructuring before the cumulative max. Restructuring resets days_past_due, so a restructured loan re-enters at current and, without the cumulative maximum carrying its pre-restructure worst state, reads as a cure.
- Fix the denominator once as the count of distinct loan_id per origination_month across the whole cohort. Prepaid and charged-off loans stop producing rows, so a denominator recomputed at each age silently shrinks exactly where losses land.
- Aggregate with groupby(['origination_month','months_on_book'])['ever_90'].sum(), then pre-build the output frame indexed by sorted origination months with integer columns 0 to 12 and assign from the grouped Series by .loc on its index.
- Mask cells beyond each cohort's maximum observed months_on_book so an immature cell reads NaN instead of an artificially low rate.
Worked solution (30 min)
- Sort by loan_id and months_on_book, build the ever_90 indicator, then apply groupby('loan_id')['ever_90'].cummax().
- Compute cohort_size as the distinct loan_id count per origination_month, before any filtering on age.
- Group the cumulative indicator by origination_month and months_on_book and sum it to get the numerator per cell.
- Create the output frame with the sorted origination months as index and range(0, 13) as columns, fill it from the grouped Series, and divide each row by its cohort_size.
- Compute each cohort's maximum observed months_on_book and set every cell to the right of it to NaN.
Expected result: A DataFrame with one row per origination_month and columns 0 to 12, values non-decreasing left to right within every row, near zero in column 0, and NaN forming an upper-right triangle where cohorts have not yet aged.
Verify it yourself
- Every row is non-decreasing across columns; a decrease means the cumulative maximum was not applied or a restructure reset leaked through.
- The denominator per row equals the cohort's distinct loan count and does not change across columns.
- Column 0 is at or near zero for every vintage, since a loan cannot be 90 days past due at its first month end.
- origination_month plus months_on_book is constant along an anti-diagonal, so one anti-diagonal should reproduce a direct calendar-month filter.
Follow-up
- Two adjacent vintages diverge at months_on_book 6. How would you separate seasoning, mix shift and a genuine credit-quality change?
- The three most recent vintages look best on this table. What do you check before saying so?
- How does the table change if charge-off policy moved from 180 to 120 days past due partway through the series?
Customers with no credit application, avoiding the NOT IN trap
Medium · null semantics · anti-join · scd type 2
Count current customers who have never submitted a credit application, broken out by segment. dim_customer is a slowly changing dimension type 2, so restrict to is_current = true, kyc_status = 'verified' and closed_at null. In fct_loan_application, customer_id is null for applicants who were not customers when they applied. Write the anti-join, return segment and customer_count, and state in one line what NOT IN (SELECT customer_id FROM fct_loan_application) returns against this table and why.
Approach
- Pin the dimension to one row per customer first: is_current = true already guarantees that, but say so out loud, because forgetting it multiplies every count by the number of attribute versions a customer has accumulated.
- Write the anti-join as NOT EXISTS with a correlated predicate on customer_id, which evaluates per row and is unaffected by nulls anywhere in the applications table.
- Name the failure explicitly: NOT IN against a nullable column compares each candidate to a set containing NULL, the comparison yields UNKNOWN rather than TRUE, and the whole predicate is therefore never satisfied, so the query returns zero rows.
- If NOT IN is required for some reason, add WHERE customer_id IS NOT NULL inside the subquery, which restores the intended semantics, and note that a LEFT JOIN with an IS NULL filter is equally safe.
- Group by segment and sanity-check the total against the unfiltered current-customer count minus the count of distinct applying customers.
Follow-up
- Rewrite it as a LEFT JOIN with IS NULL and say when you would prefer that form to NOT EXISTS.
- How does the answer change if you want customers who never applied as of a historical date rather than today?
- The applications table has 40,000 rows with a null customer_id. What are those rows, and are they a data quality problem or a product fact?
Vintage ninety-plus rate at twelve months on book
Medium · vintage analysis · window functions · right censoring
From fct_loan_performance_monthly, build a vintage table keyed on origination_month: the share of each cohort that ever reached days_past_due of 90 or more, or charge_off_flag = true, at or before months_on_book = 12. Restructuring resets days_past_due, so for any loan with restructured_flag true, evaluate only the month ends strictly before its first restructured month. Return origination_month, loans_funded, bad_loans and bad_rate. Exclude any cohort that does not yet have a months_on_book = 12 observation for every loan still on book.
Approach
- Establish the cohort denominator from the first month end each loan appears at, months_on_book = 0, so a loan is counted once in its origination_month rather than once per monthly row.
- Find each loan's first restructured month with MIN(as_of_month_end) FILTER (WHERE restructured_flag) OVER (PARTITION BY loan_id), or the equivalent grouped subquery, and keep it null for loans never restructured.
- Flag a loan bad if any row with months_on_book <= 12 and as_of_month_end earlier than that first restructured month has days_past_due >= 90 or charge_off_flag = true, which is what 'pre-restructure worst state' means in practice.
- Gate maturity by requiring the cohort's newest month end to be at least 12 months after origination_month, and report immature cohorts as incomplete rather than letting them appear at a flattering low rate.
- Aggregate to one row per origination_month and read the column downward, not across calendar time, because the whole point is comparing cohorts at equal age.
Worked solution (35 min)
- CTE 1: per loan_id, derive origination_month, the first restructured month end, and the maximum months_on_book observed.
- CTE 2: join back to the monthly rows, filter to months_on_book <= 12 and to month ends before any restructure, then flag bad with a BOOL_OR.
- CTE 3: aggregate to origination_month with COUNT() as loans_funded and COUNT() FILTER (WHERE is_bad) as bad_loans.
- Apply the maturity gate and compute bad_rate with a numeric cast.
Expected result: One row per matured origination_month with loans_funded, bad_loans and a bad_rate between 0 and 1. The most recent immature cohorts are absent from the output entirely rather than present with a small bad_rate.
Verify it yourself
- SUM(loans_funded) across reported cohorts equals COUNT(DISTINCT loan_id) restricted to those same origination months.
- Recomputing without the months_on_book cap raises bad_rate monotonically for every cohort, and raises it most for the oldest, which is the seasoning effect made visible.
- No cohort in the output has a maximum months_on_book below 12.
Follow-up
- Should a restructure inside 12 months count as bad in its own right? Argue both sides and say what you would actually ship.
- A loan that prepaid in full at month 4 never had a chance to go 90 days past due. In or out of the denominator, and why?
- The 2025-11 cohort is two points worse at month 12 than its neighbours. What three queries do you run before you call it a credit-quality change?
Describe your process for verifying factual claims within a long-form generated response.
Medium
Approach
- State your assumptions explicitly before working the problem.
- Clarify what is being asked and what a complete answer would contain.
- Work from the decision backwards to the evidence you would need.
Follow-up
- What assumption would you test first?
- How would you know your answer was wrong?
How would you design a rubric to grade the quality of an AI’s explanation of a complex mathematical proof?
Medium
Approach
- Say what you would check first and why it is the highest-information step.
- Work from the decision backwards to the evidence you would need.
- State your assumptions explicitly before working the problem.
Follow-up
- What assumption would you test first?
- How would you know your answer was wrong?
Size a two-week test on the ecommerce authorization path
Easy · power · mde · ratio metrics · clustering
Your team wants to test a new decline-retry policy on the ecommerce channel. The metric is the dollar-weighted authorization approval rate from fct_payment_authorization: approved amount_minor over attempted amount_minor, after collapsing retry chains within a 15-minute window on (card_token_id, merchant_id, amount_minor) and excluding is_reversal rows and zero-amount verifications, all converted to one reporting currency. Baseline is 87 percent on roughly 900,000 collapsed attempts in two weeks. Randomisation is by customer_id, mean six attempts per customer. Give the minimum detectable effect at 80 percent power, two-sided alpha 0.05, and say what you would change if it is too large.
Approach
- Compute the count-weighted binomial anchor first, because it is the number everyone expects and you need it to show why it is wrong. With n = 450,000 attempts per arm and p = 0.87, MDE = (1.96 + 0.8416) * sqrt(2p(1-p)/n).
- State that the real metric is a ratio of two sums with a random denominator, not a Bernoulli mean, so the binomial standard error is not the right one. Linearise: Var(R) is approximately Var(Y_i - R * D_i) / (n * Dbar^2), where Y_i and D_i are the approved and attempted amount totals for customer i, n is the number of customers, and Dbar is the mean attempted amount per customer.
- Apply the clustering correction, since assignment is by customer and attempts within a customer are correlated. Ask for or estimate the intra-customer correlation; the design effect is 1 + (m - 1) * rho with m = 6, so rho = 0.05 gives 1.25 and inflates the MDE by sqrt(1.25) = 1.118.
- Do not assume the amount-weighted variance; estimate it by bootstrapping customers from the last eight weeks of history and resampling whole customers, which captures both the skew in amount_minor and the within-customer correlation in one step.
- If the MDE exceeds the plausible effect, list the levers in order of cost: extend duration (MDE falls as 1/sqrt(n)), restrict to the segment where the rule can bind at all rather than diluting across all traffic, apply CUPED on the customer's pre-period approved amount, or switch the primary to the count-weighted rate and demote the dollar-weighted rate to a secondary read.
Worked solution (20 min)
- Split 900,000 collapsed attempts into 450,000 per arm and compute the binomial anchor: sqrt(2 * 0.87 * 0.13 / 450000) = sqrt(5.027e-7) = 7.090e-4; multiply by 2.8016 to get 1.99e-3.
- Derive the customer count: 900,000 / 6 = 150,000 customers, 75,000 per arm, and note that this is the true sample size for inference.
- Apply the design effect at rho = 0.05: 1 + 5 * 0.05 = 1.25, so the count-weighted MDE becomes 1.99e-3 * 1.118 = 2.22e-3.
- State that the dollar-weighted MDE requires the linearised variance and cannot be derived from p alone; specify the customer-level bootstrap that would produce it and note it will be larger because amount_minor is right-skewed.
Expected result: Count-weighted MDE is about 0.20 percentage points unclustered and about 0.22 percentage points at a design effect of 1.25, against an 87 percent baseline (roughly 0.26 percent relative). The dollar-weighted MDE is not computable from the stated inputs and must be estimated by a customer-level bootstrap; the candidate should say so rather than quote the binomial figure for it.
Verify it yourself
- z(0.975) + z(0.80) = 1.9600 + 0.8416 = 2.8016; any MDE quoted with a different multiplier is using different power or alpha than stated.
- Doubling the test duration should shrink the MDE by exactly sqrt(2) = 1.414 if the traffic mix is stable; if a candidate's arithmetic does not, the formula is wrong.
- Run the bootstrap on two historical periods split A/A: the bootstrap standard error of the difference times 2.8016 should reproduce the analytic MDE.
- A/A splits of historical data should reject at roughly 5 percent; materially more means the variance model is understated.
Follow-up
- The rule only changes behaviour on declined attempts, which are 13 percent of traffic. How does restricting the analysis population to attempts that could have triggered the rule change both the MDE and the estimand?
- How would your sizing change if the split were 90/10 instead of 50/50, and why is the loss more than proportional?
- Currency: the metric sums amounts converted to one reporting currency. Would you use settlement_fx_rate or a rate table pinned at test start, and what does the choice do to variance?
Fraud losses appear to halve in recent transaction months
Medium · right censoring · development factors · maturity
A weekly chart attributes fct_card_dispute cases to the requested_at month of the linked fct_payment_authorization row. The two most recent months show the first-chargeback rate falling by half, and a risk rule shipped six weeks ago. Columns: dispute_id, auth_id, dispute_category, dispute_stage, opened_at, disputed_amount_minor, liability_shift_flag, outcome, net_loss_minor, resolved_at. Decide whether the rule worked, and produce the version of the chart you would sign your name to.
Approach
- Separate the two dates explicitly. opened_at is when a case was filed, requested_at is when the transaction happened. Attributing by transaction month is the right causal choice and is exactly what makes the newest months structurally incomplete.
- Measure the filing lag rather than assuming it: the distribution of opened_at minus requested_at over fully developed months, split by dispute_category, and the age at which around 95 percent of cases have arrived.
- Build a development triangle of transaction month by months of development on cumulative case counts, and estimate age-to-age factors from the columns that are complete.
- Develop the immature months with those factors and plot the result as an estimate with a visible band, kept visually distinct from the matured series rather than blended into it.
- State the assumption the method needs: a stable development pattern across cohorts. A change in filing behaviour, merchant mix or the dispute team's own backlog breaks it, so inspect factor stability down each column before relying on the estimate.
- Only then evaluate the rule, comparing pre-change and post-change cohorts at equal development age.
Follow-up
- What leading indicator would you accept while the cohort matures, and what is its known bias?
- How does liability_shift_flag change which disputes you should expect to see in the first place?
- If the rule also blocked good transactions, where does that cost appear, and is any of it in this chart?
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.
Your part, not the team's
Most data work is done by groups, so an interviewer has to work out which piece was yours. An answer that runs on 'we' for several minutes gets interrupted with a question about what you personally did, and by then the answer sounds defensive even when it is true. Mark your own contribution as you go, and name the parts that belonged to someone else instead of leaving them ambiguous. Keep a few specifics back as well, like the name of the metric or who actually objected, so a probe can be answered with something you had not already said.
How do you handle ambiguous prompts where the user’s intent is unclear but the desired output is technical?
Medium · behavioural and stakeholder questions
Approach
- 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.
- Pick a story where you drove the decision, not one where you observed it.
Follow-up
- What would you do differently if you ran that project again?
- What did you decide not to do, and why?
Describe a time you had to correct a model’s faulty logic; what was your systematic approach?
Medium · behavioural and stakeholder questions
Approach
- Quantify the outcome, including what you would not claim credit for.
- Close with what you would do differently, concretely.
- 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?
Recommend a decision whose true outcome matures a year later
Hard · decision under censoring · leading indicators · staged rollout
An underwriting rule change must be decided in six weeks. Its real outcome, the vintage 90-plus rate at months_on_book 12 in fct_loan_performance_monthly, matures in a year. The executive wants a yes or no, not a range. Randomising the credit decision across the whole population is not available. Name the leading indicator you would accept, state its bias and the direction of that bias, define the decision rule and stopping condition before any rollout starts, and say what reading would make you recommend reversing the change.
Approach
- Fix the readout before the rollout, because a readout chosen after the data arrives is a story rather than a decision rule: indicator, window, threshold and reversal condition all go in writing first.
- Choose the leading indicator on its measured relationship to the matured outcome in historical vintages rather than on availability. Early delinquency, typically the share reaching dpd_1_29 or missing a first scheduled payment by months_on_book 3, is the usual candidate, and you quantify how well it predicted the 12-month rate across past cohorts.
- State the bias and its direction plainly: early delinquency under-represents default that emerges later and is contaminated by servicing and payment-date effects, so treat it as a floor on risk rather than an estimate of it.
- Buy identification where full randomisation is unavailable: a narrow randomised approval band around the cutoff, or a staged rollout by channel or region read as a difference-in-differences, with the parallel-trends assumption stated and checked in the pre-period rather than assumed.
- Give the executive the binary they asked for with the trigger attached in the same sentence: yes, conditional on the month-3 indicator staying inside a stated band, with an automatic hold if it breaches.
Follow-up
- How would you validate that the month-3 indicator predicts the 12-month outcome, and what evidence would invalidate it mid-rollout?
- Compliance refuses a randomised band. What is your next-best identification strategy, and what precision do you lose by taking it?