Interview guides · AIRBUS U.S. Space & Defense
AIRBUS U.S. Space & Defense Data Scientist Interview Questions & Guide 2026
Data scientist prep for AIRBUS U.S. Space & Defense candidates: drill A/B design, power and minimum detectable effect on original exercises.
The 60-second brief
As a Data Scientist at AIRBUS U.S. Space & Defense, you are at the forefront of aerospace innovation and national security. This role is not just about building models; it is about extracting actionable intelligence from massive, complex datasets generated by satellites, aircraft, and defense systems. Your work directly impacts mission-critical operations, predictive maintenance for multi-million-dollar assets, and strategic decision-making in high-stakes environments.
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
- Separate obligations, outlays and ceilings correctly
- Model censored case durations without survivorship bias
- Audit disparate impact before any model ships
Overview
You will collaborate with cross-functional teams of aerospace engineers, product managers, and software developers to solve unprecedented challenges. Whether you are optimizing flight trajectories, analyzing telemetry data to predict component failures, or enhancing satellite imagery processing, your algorithms will operate at a massive scale. The problems you solve here require a blend of rigorous statistical thinking, advanced machine learning, and a deep appreciation for the physical constraints of aerospace engineering.
Expect an environment that balances the meticulous safety and reliability standards of the aerospace industry with the fast-paced innovation of modern data science. Candidates who thrive here are those who are inspired by the mission, comfortable navigating complex technical requirements, and capable of translating abstract data into tangible, real-world impact.
The AIRBUS U.S. Space & Defense interview process
AIRBUS U.S. Space & Defense candidates report 3 rounds · ≈ 3-5 weeks. The stages below are what candidates describe, not a published process.
Pre-Recorded Video Interview
An added round often puts you in front of someone outside the core hiring team: a partner engineer, a product owner, a domain expert, sometimes a more senior manager. The question they are really asking is not whether you can do the work but whether they would trust a number that came from you. That changes what a good answer looks like. Lead with what the decision cost and what it changed, keep the method available but not central, and be plain about the limits of your evidence. Overstating a result is the fastest way to lose this round.
What to demonstrate
- Whether you can explain a technical choice to someone who will never read your code, without either flattening it into nothing or hiding inside jargon
- Honesty about evidence strength: what the analysis establishes, what it only suggests, and what it cannot say at all
- How you take disagreement, specifically whether you update on a good objection, hold your position with reasons, or fold on contact
How to prepare
- Write the two-sentence version of your most technical project for a non-specialist, then check that neither sentence needs a method name to make sense.
- For one result you are proud of, write the strongest objection someone could raise and a response that concedes the part of it that is correct.
- Prepare one decision that turned out to be wrong: how you found out, what it cost, and what you changed afterwards. A senior cross-functional interviewer asks for this more often than a technical one does.
Technical Interview
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
Final Team Interview
A day of back-to-back interviews samples your floor, not your ceiling. Four hours in, the habits that carry a good answer are the first to go: restating the question before solving it, asking what the data would have to look like, checking a number before quoting it. What the day decides is whether the tired version of you is still someone to leave alone with an ambiguous problem. The round that sinks a candidate is usually not the hardest one. It is the one immediately after the round that went badly.
What to demonstrate
- Whether the late rounds get the same clarifying questions as the first one, or whether you start answering immediately to save effort
- Whether a weak answer stays in the room it happened in, instead of following you into the next conversation as apology or distraction
- Whether the quality of your questions holds up, since fatigue removes curiosity about the problem before it removes knowledge of the method
How to prepare
- Rehearse the length, not just the content: book four mock interviews of different types in one afternoon with short gaps, because the one you need to observe is the fourth
- Put the two or three questions you ask at the start of any problem on a card in front of you, so that under fatigue it is a habit you run rather than a decision you make
- Decide in advance what the gap between rooms is for: water, one line of notes on anything you promised to follow up, and an explicit close on the round that just ended so it does not travel
- Prepare a different closing question for each interviewer, so the end of a long day does not produce the same one four times
Where candidates lose points
Suppressing one small cell in a published table and leaving the row and column totals in place
A single suppressed cell is recoverable by subtracting the published cells from the published margin, so primary suppression without complementary suppression protects nothing. Two separately published tabulations of the same underlying data compose as well, meaning two individually safe releases can jointly identify a cell. Either apply complementary suppression across the whole table and check it against the margins, or use a formal mechanism with an accounted budget, remembering that Laplace noise for a count query is scaled to sensitivity over epsilon, that sequential releases add their epsilons, and that noisy counts are not automatically non-negative or additively consistent across aggregation levels until post-processed.
Dividing an administrative count by a survey population estimate and reporting the rate as if it were exact
At block-group and tract scale the published margin of error is often a large fraction of the estimate, so the variance of the resulting rate is dominated by the denominator rather than the numerator, and a leaderboard of areas ranked by point estimate is largely a leaderboard of the smallest and noisiest areas. Propagate the denominator error into the rate, or aggregate up until the relative standard error is acceptable, and state the threshold used. The same join also breaks silently across boundary vintages: a geo_code can refer to a different physical area after a redraw, so joining current-vintage geography onto historical events reassigns records and manufactures a trend break.
Reporting a mean for a heavy-tailed metric without saying what it hides
For spend, session length or items per order, a small fraction of units carries most of the total, so the mean has a wide standard error and one account can move it. Fix the handling before you see the result: cap or winsorise at a pre-declared percentile, and report the median or the share above a threshold next to the mean. Capping changes the estimand, so say which question the capped number answers, and check how much of any difference comes from the top 0.1 percent of units.
Accepting a metric definition without asking about the denominator
Pin down the denominator, the eligibility filter and the time window before computing anything: conversion rate per session, per user, per eligible user and per new user are four different numbers with different behaviour. Restate the definition in one sentence and get agreement before you analyse.
Questions & practice
Explain the trade-off between bias and variance, and how you manage it in your models.
Medium · statistics and probability
Approach
- Sanity-check the answer against a simple bound or a simulated case.
- Write down the assumption the method needs before you use the method.
- Say what the estimate is of, and over what population it generalises.
Follow-up
- What sample size would you need to detect an effect half this size?
- Which assumption here is most likely to be violated in practice?
What techniques do you use to prevent data leakage during feature engineering and cross-validation?
Medium · machine learning and modelling
Approach
- Check what information would not exist at prediction time, and exclude it.
- Frame the prediction: the label, the moment of prediction, and the action it triggers.
- 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?
Explain how a Random Forest algorithm works under the hood to a non-technical manager.
Medium · machine learning and modelling
Approach
- Say how the offline result would be validated online before it is trusted.
- Frame the prediction: the label, the moment of prediction, and the action it triggers.
- 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?
How do you evaluate the performance of an anomaly detection model when true anomalies are extremely rare?
Medium · machine learning and modelling
Approach
- Check what information would not exist at prediction time, and exclude it.
- Frame the prediction: the label, the moment of prediction, and the action it triggers.
- 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?
Resolve service-request reopen chains and score the 30-day rate
Hard · graph traversal · sessionisation · reopen rate
requests has service_request_id, reported_at, closed_at, closure_code, request_type_code and reopen_of_request_id, a nullable self reference to the earlier request this one repeats. Resolve the chains into episodes: give every row a root id, a depth and an ordinal, without recursion and without looping forever on a cycle. Then compute the 30-day reopen rate, where the denominator is requests closed in the window with closure_code 'resolved' and the numerator is those with a child reported within 30 days of closed_at. Report dangling parent references and any cycle you find.
Approach
- Separate genuine roots (reopen_of_request_id is null) from dangling references where the parent id is absent from the table. Rooting a dangling child silently welds two episodes together and hides an extract that was cut mid-chain.
- Walk with iterative pointer jumping: each pass remaps every row to its parent's parent, so the remaining distance to the root halves per pass and about 20 passes cover a chain a million deep. Point every root at itself so the jump is a no-op once a row has arrived, and stop when no pointer changes rather than at a fixed count.
- Carry a distance vector alongside the pointer or the depth column is wrong. Under doubling a row at true depth d stops moving after about ceil(log2 d) passes, so the pass number is log2(depth) and not depth: a chain 8 deep stabilises on pass 3. Hold dist with the invariant that dist[i] is the number of edges from i to ptr[i], initialised to 1 for every child and 0 for every root, and update dist[i] += dist[ptr[i]] and ptr[i] = ptr[ptr[i]] together from the previous pass's arrays. At the fixed point ptr[i] is the root and dist[i] is the true depth.
- Detect cycles by capping iterations at ceil(log2(n)) + 1 and flagging rows whose pointer is still moving. A cycle means a request was recorded as a reopen of its own descendant, which is a data error and must be quarantined rather than reported as an episode.
- Assign ordinal within root by reported_at, then compare that ordering against the foreign-key chain order. Disagreement means backdated reported_at values and belongs in the data-quality report, not silently inside the metric.
- For the metric, join each qualifying closed request to its children and keep those with 0 <= reported_at - closed_at <= 30 days. A child reported before its parent closed is an error, not a reopen, and counting it inflates the numerator.
- Apply the exclusion of duplicate, invalid and closed_on_age to both numerator and denominator, then report the rate both ways so the size of the flattery is on the page rather than in a footnote.
Worked solution (40 min)
- Build a parent Series indexed by service_request_id, mark ids whose parent is not in the index as dangling, and set those pointers to null with a reason recorded.
- Initialise ptr = parent.fillna(own id) and dist = parent.notna().astype(int), then iterate on the previous pass's values: dist_next = dist + ptr.map(dist) and ptr_next = ptr.map(ptr), assigning both together. Stop at a fixed point of ptr or at the iteration cap, and treat rows still moving at the cap as cycle candidates.
- Read depth off the final dist rather than off the pass number at which a row stabilised, which is log2 of the depth, then rank reported_at within root for ordinal and diff ordinal against depth.
- Filter the denominator to closed_at in the window with closure_code == 'resolved', left-join children on reopen_of_request_id, and count parents with at least one child inside the 0 to 30 day band.
- Recompute the same numerator against a denominator that keeps administrative closures, and return both rates with the episode frame, the dangling list and the cycle list.
Expected result: An episode frame carrying root_id, depth and ordinal for every request; a list of dangling parent ids; an empty cycle list on clean data; and the 30-day reopen rate. With administrative closures left in the denominator the rate is lower, and if those closures have no children the two rates differ by exactly the factor (resolved closures / all closures).
Verify it yourself
- Every row reaches a fixed point within the iteration cap, and the count of distinct roots plus the count of non-root rows equals the total row count.
- No row is its own ancestor: applying the final root map a second time changes nothing.
- Counting parents with a qualifying child and counting qualifying children agree only when no parent has two children inside the window; where they differ, the parent-side count is the one the definition asks for.
- Rows excluded as dangling or cyclic are listed and, added back to the matched rows, account for the full table.
- depth is 0 for every root and equals the parent's depth plus 1 for every non-dangling child, asserted directly against the parent map. That equality is what separates a true depth from the pointer-doubling pass count, which would report 3 for a chain of depth 8.
Follow-up
- Two crews close the same kind of work differently, one as 'resolved' and one as 'referred_external'. What does that do to this metric, and how would you detect it from this table alone?
- A chain crosses a request_type_code retirement, so parent and child carry different codes. How do you attribute the episode, and what do you report by type?
- The rate is 12 percent overall and 3 percent in one district. Give two explanations that are not about work quality.
Point-in-time join across slowly changing dimension and boundary vintage
Hard · scd type 2 · point-in-time join · fan-out
fact_application has application_id, constituent_id and submitted_at. dim_constituent is type 2 with constituent_id, residence_geo_id, effective_from and effective_to (NULL marks the current row). dim_geography has geo_id as the primary key, unique to one geography and one boundary vintage, plus geo_code, vintage_year, effective_from, effective_to and deprivation_quartile; the same geo_code refers to different physical areas in different vintages. Count applications submitted between 2021 and 2025 by submission year and by the deprivation quartile of the residence as it stood on submitted_at. Exactly one output row per application must feed the count.
Approach
- Join dim_constituent with a range predicate, submitted_at >= effective_from AND (effective_to IS NULL OR submitted_at < effective_to), using a half-open interval so an application submitted exactly at a version boundary matches one version and not two.
- Join dim_geography on residence_geo_id, not on geo_code: geo_id is already unique to the geography-and-vintage pair, so it carries the vintage for free, while geo_code multiplies each application by the number of vintages that code has existed in and reassigns records across a redraw.
- Assert the grain rather than assuming it, by counting rows before and after each join; a type 2 dimension joined on the natural key alone produces one row per version of the person and the inflation is largest for constituents who moved, which is exactly the population a quartile breakdown is about.
- If the dimension has overlapping ranges from a bad load, deduplicate with ROW_NUMBER() OVER (PARTITION BY application_id ORDER BY effective_from DESC) and keep rn = 1, but record how many applications needed it instead of hiding the repair.
- Report the count of applications that failed to match any version as its own line, because a point-in-time join that silently drops pre-history applications understates the earliest years and produces a fake upward trend.
Follow-up
- A boundary redraw happened in 2023. What exactly goes wrong in a year-over-year quartile comparison if you attach current-vintage geography to every year, and which direction does it bias?
- How would you present a 2021-to-2025 trend when the quartile definitions themselves were re-derived within each vintage?
- Some applications match no constituent version because the identity was resolved after submission. Include them, exclude them, or report separately?
Submission completion rate by intake channel, thirty-day window
Easy · funnel · cohorts · conditional aggregation
fact_application has application_id, channel (online, phone, mail, in_person, kiosk, partner_org), created_at, submitted_at (NULL if the draft was never submitted) and status. Report, per weekly created_at cohort and per channel, the number of applications started, the number submitted within 30 days of created_at, and the completion rate. Include only cohort weeks that closed at least 30 days before the extract date. Rows left in status 'draft' or 'abandoned' stay in the denominator. Return cohort_week, channel, started, submitted_30d, completion_rate.
Approach
- Bucket on created_at, not submitted_at: the cohort is defined by when the work entered the system, so a row that never submits must still land in a cohort week.
- Express the numerator as a conditional aggregate, COUNT() FILTER (WHERE submitted_at IS NOT NULL AND submitted_at < created_at + INTERVAL '30 days'), so the denominator stays COUNT() over the same grouped set and cannot drift from it.
- Cut incomplete cohorts with a WHERE on the cohort week rather than on individual rows, and anchor the maturity test on the week's last possible created_at, not its first. A week runs [week_start, week_start + 7 days), so the latest application in it needs 30 more days and the week qualifies only when week_start + INTERVAL '37 days' <= extract_date. Testing week_start + 30 days admits a week whose Sunday arrivals have had 23 days of exposure, and that week reports a depressed rate that reads as a regression.
- Group by channel from the start rather than pooling then splitting, because channel mix changes week to week and a pooled rate moves with the mix.
- Return the raw numerator and denominator next to the rate so a reader can see which channels carry enough volume for the rate to mean anything.
Worked solution (20 min)
- Write the cohort key as date_trunc('week', created_at) and confirm the row count of the base table equals the sum of the started column, proving nothing was dropped by the grouping.
- Add the 30-day conditional count and verify submitted_30d never exceeds started for any group.
- Filter to cohort weeks where date_trunc('week', created_at) + INTERVAL '37 days' <= extract_date: 7 days to carry the week out to its last created_at, plus the 30-day submission window. Under date_trunc a week starts Monday, so this is the Monday whose following Sunday's arrivals have all had their full 30 days.
- Compute completion_rate as submitted_30d::numeric / NULLIF(started, 0) to avoid a divide-by-zero on a channel with no starts in a week.
- Scan the output for channels sitting at exactly 1.000 and note them as a measurement artefact rather than a result.
Expected result: One row per (cohort_week, channel) pair with started > 0, completion_rate in [0, 1]. mail and in_person return 1.000 in every week because those channels have no draft state, so created_at and submitted_at are written in the same transaction. online and kiosk return rates strictly below 1 and are the only channels where the metric carries information.
Verify it yourself
- SUM(started) across all output rows equals COUNT(*) of fact_application restricted to the same created_at range and the included cohort weeks.
- No row has submitted_30d > started.
- Relaxing the anchor from 37 days to 30 days admits exactly one further cohort week, and that week's online and kiosk rates sit visibly below their neighbours; dropping the filter entirely extends that depressed tail. Both confirm the maturity cut is doing work and that 30 days is the wrong anchor.
- A count of rows with status IN ('draft','abandoned') is non-zero and is exactly the shortfall between started and applications ever submitted.
Follow-up
- mail and in_person come back at exactly 1.000 every week. Is that a bug, and how would you present the metric so a reader does not read it as those channels performing best?
- How would the query change if you wanted completion within 30 days measured in business days against the published service standard instead of calendar days?
- A channel's completion rate rises 8 points the week a new form launches. What would you check before reporting it as an improvement?
Walk me through the most complex data science project on your resume from start to finish.
Medium
Approach
- Work from the decision backwards to the evidence you would need.
- 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?
How would you design a predictive maintenance system for a fleet of vehicles or aircraft?
Medium
Approach
- Clarify what is being asked and what a complete answer would contain.
- Work from the decision backwards to the evidence you would need.
- State your assumptions explicitly before working the problem.
Follow-up
- How would you know your answer was wrong?
- What assumption would you test first?
Variance reduction with pre-period covariates and stratified blocks
Medium · cuped · stratification · variance reduction
A district-level experiment on a reminder for outstanding evidence will run six weeks across 46 service districts. The outcome is the share of evidence requests satisfied within 14 days, computed per district. District outcomes are stable: the correlation between a district's pre-period share and its in-period share is 0.62. You have 23 districts per arm and cannot get more. Specify a CUPED adjustment and a stratification scheme, and quantify what each one buys in MDE terms.
Approach
- Choose a covariate fixed before randomisation and untouchable by treatment: the same district's pre-period outcome over a window ending before assignment, which is why that window has to be frozen in the design document rather than chosen after seeing results.
- Apply the adjustment as Y_adj = Y - theta * (X - mean(X)) with theta = Cov(Y, X) / Var(X), the ordinary least squares slope of Y on X estimated on the pooled arms; the estimate stays unbiased because X is pre-randomisation and the same theta is applied to both arms.
- Quote the variance result exactly: Var(Y_adj) = Var(Y) * (1 - rho^2), so the standard error falls by sqrt(1 - rho^2), the MDE falls by the same factor, and the effective sample multiplies by 1 / (1 - rho^2).
- Stratify instead of simple-randomising: block on deprivation quartile crossed with a pre-period volume tercile, assign inside blocks, and then include the block indicators in the analysis model, because a stratified design analysed without strata terms is valid but conservative and throws the gain away.
- State the limits plainly: CUPED reduces variance and does nothing about bias, it cannot rescue a broken assignment, and at 46 units the gain competes with the degrees of freedom the adjustment costs, so report adjusted and unadjusted estimates side by side.
Worked solution (30 min)
- Compute 1 - rho^2 = 1 - 0.62^2 = 0.6156, the multiplicative factor on the variance.
- Standard error ratio = sqrt(0.6156) = 0.785, so the MDE falls by 21.5 percent.
- Effective sample multiplier = 1 / 0.6156 = 1.62, so 46 districts behave like about 75.
- Estimate theta as the OLS slope of in-period on pre-period share across all 46 districts, then difference the adjusted arm means.
Expected result: CUPED at rho = 0.62 cuts the standard error to 78.5 percent of its unadjusted value, a 21.5 percent smaller MDE, worth about 1.62 times the sample. Stratified blocks on deprivation quartile by volume tercile guarantee balance on those margins and must be carried into the analysis model to be worth anything.
Verify it yourself
- At rho = 0 the adjustment must leave the variance unchanged; a gain there means theta is being fit on something post-treatment.
- The CUPED point estimate should sit close to the unadjusted difference in means with a visibly narrower interval; a large shift in the point estimate signals covariate imbalance or a post-treatment covariate.
- Regressing Y on X and a treatment indicator should reproduce the CUPED estimate to within rounding.
Follow-up
- What breaks if you use a covariate measured during the experiment window, such as in-period request volume, instead of a pre-period one?
- Would you rather have rho = 0.62 on 46 districts or rho = 0 on 70 districts, and how do you decide?
Equity ratio doubles after a new reporting channel opens
Hard · censored quantiles · mix shift · equity audit
The rolling-90-day first-response equity ratio (the 90th percentile response time in deprivation quartile 4 divided by the same percentile in quartile 1) moved from 1.3 to 2.6 in one month. Tables: fact_service_request (reported_at, first_response_at, request_type_code, priority, channel, geo_id, assigned_unit_id, sla_hours, closure_code) and dim_geography (geo_id, deprivation_quartile, vintage_year). Decompose the move into measurement, mix and real service change, and attach an interval to the residual.
Approach
- Handle censoring before anything else. A percentile of (first_response_at minus reported_at) computed over responded rows only is biased downward, because requests still awaiting a first response are exactly the slow ones and carry NULL. Either estimate the time-to-first-response quantile with those rows right-censored at the extract date, or switch to the share responded inside sla_hours, restricted to requests whose SLA window closed before the extract so a NULL is a definite miss.
- Verify the metric is computed within request_type_code and priority and only then aggregated with fixed weights. The mix of request types differs by quartile, so a pooled percentile ratio measures mix. A new channel such as sensor or mobile_app entering one quartile with a near-instant automated first response will crush that quartile's percentile and double the ratio with no change in field service.
- Cut by assigned_unit_id and by shift. Units are not evenly distributed across quartiles, so a vacancy, a reassignment or a queue transfer moves one unit's right tail and therefore one quartile's percentile. Check whether the move is a single unit before calling it a systemic gap.
- Check the geography join and the quartile derivation. deprivation_quartile is derived within parent geography and vintage, so a re-derivation or a vintage change reshuffles which areas sit in quartile 4, and the two quartiles being compared may not contain the same places as last month.
- Separate mix from within-cell change by recomputing with base-period weights across request type and priority, then bootstrap the residual: resample requests with replacement within each quartile stratum, recompute the percentile ratio a thousand times, and report the percentile interval, because a ratio of order statistics in a heavy right tail has no usable closed-form standard error.
Follow-up
- The whole move is a new automated channel in quartile 1. Is the equity finding therefore void, or is there still a real disparity to report, and how do you frame it?
- How would you redesign this metric so that adding a channel cannot move it, while it still detects a genuine widening?
Suggested practice checklist
Four days spend equal time on query work, statistics, modelling and product judgement at deliberately shallow depth, which produces a scored map of where you actually stand. The last three days spend everything on the two areas the role weights most, and close by re-running day one to measure movement.
Day 1 — Breadth pass: query fluency
- Solve six prompts spanning aggregation, joins, window functions and date arithmetic in 60 minutes total, stopping at 10 minutes each whether or not it works, and mark every prompt as solved, solved slowly, or stuck.
- For each unsolved prompt write the single blocking sentence (I lost the grain, I did not know the frame clause, I could not express the date boundary) instead of reading the solution.
- Translate one pandas transformation you know well into SQL and one SQL query into pandas, checking that both return the same row count and the same totals.
Deliverable: A scored six-row table, one line per prompt, saved for the day-seven re-run.
Day 2 — Breadth pass: statistics and inference
- Answer ten short questions in writing with nothing open: what a p-value is conditional on, what a 95 percent interval covers across repeated samples, when a paired test is the right one, what the bootstrap estimates, why multiple comparisons inflate false positives, how controlling the family-wise error rate differs from controlling the false discovery rate, what power depends on, what a missed real effect costs a product, the three situations where the central limit theorem does not rescue you (small n, very heavy tails, dependent observations), and what a standard error is the standard deviation of.
- Grade yourself against a reference and count only the answers that were exactly right, not the ones that were nearly right.
- Rewrite the two weakest answers the following morning from memory in full sentences.
Deliverable: Ten graded answers with an honest count of exact hits.
Day 3 — Breadth pass: modelling
- Take one tabular dataset end to end in 90 minutes: a leakage-safe split, a baseline that is not a model (majority class or historical mean), one regularized linear model, one gradient-boosted tree, and a single evaluation metric chosen before you look at any result.
- Write why that metric fits the cost structure: precision at a fixed recall for alerting, calibration for anything feeding a price or a threshold, ranking metrics for retrieval, and note that area under the ROC curve is insensitive to class balance in a way that can flatter a rare-positive problem.
- Name the leak you were most likely to introduce (an encoding fit on all rows before splitting, or a feature computed after the label's timestamp) and write the check that would have caught it.
Deliverable: A notebook whose first cell states the metric and the baseline, plus two lines on what beat what and by how much.
Day 4 — Breadth pass: product judgement
- Answer three case prompts aloud at 15 minutes each, timing how long passes before you state a success metric.
- For one case write the first segmentation you would run and the row counts you expect per segment, so that a tiny segment cannot quietly drive the conclusion.
- Take a metric definition you did not write, from a public dashboard, a textbook, or documentation you already have open, and list every place two analysts implementing it would diverge: which rows the denominator admits, whether the unit is an account or a person, what the time window is anchored to, and what happens to data that arrives late. Then write the one question that would close the largest of those gaps.
Deliverable: Three recorded case answers plus an ambiguity list for a metric someone else defined, ending in the single question you would ask about it.
Day 5 — Depth, first area
- Rank the four areas by how many bullet points in the role description each one covers, pick the top one, and spend the entire day inside it.
- Work the six hardest problems you can find in that area and for each write the generalizable move you should have reached for first, rather than the answer.
- Re-solve the two you failed the same evening with notes closed.
Deliverable: Six generalizable moves written as instructions to yourself, not as solutions.
Day 6 — Depth, second area, and the seam between them
- Repeat the depth protocol on the second-ranked area with the same six-problem structure.
- Construct one problem that requires both areas at once, for example a metric redefinition whose effect you must validate with a test whose readout you then have to query.
- Solve your own combined problem end to end and note where the handoff between the two areas cost you time.
Deliverable: One combined problem, solved end to end, with the handoff failure written down.
Day 7 — Integration and re-measurement
- Re-run the six prompts from day one under the same clock and compare both correctness and time.
- Run a 60-minute mixed mock that moves between areas without warning, since switching cost is what breadth passes do not train.
- Write the two areas you would still fail on, and the sentence you will use in the interview when you hit one of them.
Deliverable: A before-and-after score table plus a written plan for the two remaining gaps.
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 handle situations where you have conflicting priorities or tight deadlines?
Medium · behavioural and stakeholder questions
Approach
- Quantify the outcome, including what you would not claim credit for.
- State the situation in two sentences and spend the rest on your reasoning.
- Pick a story where you drove the decision, not one where you observed it.
Follow-up
- What did you decide not to do, and why?
- How did you know the outcome was caused by your change?
Describe a time you had to convince a skeptical stakeholder to adopt your data-driven recommendation.
Medium · behavioural and stakeholder questions
Approach
- Pick a story where you drove the decision, not one where you observed it.
- Name the disagreement or constraint, and how you resolved it with evidence.
- 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?
Defend a metric redefinition that made performance look worse
Medium · metric design · stakeholder conflict · survivorship
You changed on-time decision share to count applications by sla_due_at rather than decision_at, so an application still open past its due date now sits in the denominator and not the numerator. The reported figure fell from 91 to 68 percent, two weeks before a published quarterly. An operations director says you broke the metric and wants the old number restored. You have a fifteen-minute meeting. Bring what you will show, what you will concede, and the decision you are not the one to make.
Approach
- Reconcile both numbers on the same cohort before arguing about either. Show that the 23 points are not a recomputation artefact: they are applications whose sla_due_at fell in the window and which had no decision_at at extract, a set the old definition could never sample because it selected on the decision happening.
- Make the pathology visible rather than describing it. Plot the old metric against the count of open-past-due cases over the last eight quarters; the old series rises as the backlog grows, which is the behaviour nobody would sign off on if it were proposed fresh.
- Concede the real thing: the two series are not comparable, the level change is a measurement change and not a performance change, and publishing the new number without that sentence would misrepresent the operation as having deteriorated overnight.
- Offer the mechanics that make the transition survivable: publish both definitions for the transition quarter, restate the prior four quarters on the new definition so the trend is readable, and put the definition in the published note.
- Separate the argument from the decision. You own the analysis; whoever owns the published performance definition owns the choice. Say which escalation path you will use and then use it, rather than trying to win the room.
Follow-up
- The director proposes publishing the old number this quarter and switching next quarter. What is your answer, and does it change if the quarterly is statutory?
- Restating history on the new definition needs historical sla_due_at values. What could have changed underneath them, and how do you check?