Interview guides · Hinge
Hinge Data Scientist Interview Questions & Guide 2026
Practice explaining analysis before a Hinge data scientist interview: the recommendation, the uncertainty, the follow-ups.
The 60-second brief
As a Data Scientist at Hinge, you are not just analyzing data; you are the architect of human connection. The company’s mission—to be the dating app "designed to be deleted"—places a unique burden on its data team. You are tasked with balancing complex algorithmic matching with the human element of relationships, ensuring that every user interaction moves them closer to a meaningful, long-term connection.
A large share of questions open as "how would you measure X", where the real work is choosing the metric, fixing its denominator, and defining the population it applies to. Any computation comes last and is frequently not required at all.
Focus areas
- Separate creator supply effects from viewer demand effects
- Judge ranking metrics under position bias and feedback loops
- Decompose DAU into new, retained, reactivated, resurrected
Overview
You will typically operate within product-focused teams like Matching, where your work directly influences the app’s core experience. Your daily impact involves translating abstract product objectives into measurable data science problems, designing rigorous A/B tests, and collaborating with engineers to deploy machine learning models. Because Hinge is obsessed with the metric of "setting up great dates," you will serve as a strategic partner to product managers and designers, using data to bridge the gap between user behavior and product strategy.
This role is ideal for a Data Scientist who thrives at the intersection of statistical rigor and product intuition. You will be expected to balance technical depth with the ability to influence cross-functional stakeholders. Whether you are investigating a sudden dip in engagement metrics or optimizing a recommendation engine, your work is the engine that drives the company’s mission to create a less lonely world.
The Hinge interview process
Hinge candidates report 2 rounds · ≈ 2-4 weeks. The stages below are what candidates describe, not a published process.
Initial Screening
Whoever runs this call is usually not a practitioner. They take notes, and a hiring manager skims those notes later, so the real question is whether your work survives being written down by someone outside the field. Test every project sentence against that: could a non-specialist repeat it correctly without knowing what a propensity score is? Carry a plain-language version of each project and one reason you want this particular role that you could not copy onto another application. Vagueness at this stage reads as inexperience, even when the underlying work was genuinely deep.
What to demonstrate
- Whether a non-specialist can restate your projects accurately, since their paraphrase is what reaches the hiring manager
- Whether your reason for wanting the role points at the work itself rather than the company's reputation
- Whether your language signals the level being screened for: what you decided yourself versus what you were handed
How to prepare
- Write a two-sentence, jargon-free version of each major project: the question nobody could answer, and the decision your work changed. Read it to someone outside data and have them repeat it back
- Point your 'why this role' answer at something concrete in the job description or the product surface you would be working on, and keep it to two sentences
- Have two questions ready about measurement: which metric the team is held to, and who acts on an analysis once it lands
Super Day
Where a loop includes a partner from outside the data team, that conversation usually carries the same weight as the technical ones and gets the least preparation. The person opposite you will not follow a derivation and does not need to. They are working out whether having you involved would make their decisions better or slower. The failure mode is not being too technical. It is answering a question about a decision with a description of your method, leaving the translation to them. What they carry into the debrief is the sentence you handed them, not the analysis underneath it.
What to demonstrate
- Whether a statistical result arrives as something the partner could act on, with the one caveat that would change their decision kept and the rest left out
- Whether you can state what you need from their side, in their terms: instrumentation that does not exist yet, a definition they own, or a holdout they have to agree to
- Whether uncertainty is given as a range someone can plan against, rather than as hedging that invites them to ignore the result
- Whether you ask what decision is actually on the table before explaining anything
How to prepare
- Take a result you know well and write the version for someone who stops reading after one sentence, then the three-minute version, and check the short one is not the long one with the qualifications stripped out
- For a past project, list everything you asked a non-technical partner for and how you phrased it, then rewrite each ask so it names what goes unmeasured without it
- Practise saying where a result does not apply, out loud, in one sentence that a partner could repeat accurately to someone else
Where candidates lose points
Averaging per-member engagement when the distribution is heavy-tailed
Time spent, impressions and authored actions per member are extremely right-skewed, so the sample mean has high variance and a handful of members can move a reported lift past significance on their own. Two specific errors follow. Averaging per-member rates (mean of ratios) answers a different question from total engagements over total members (ratio of sums), and the two diverge whenever the heavy users behave differently. Capping or winsorising reduces variance but changes the estimand, so the cap must be pre-registered and reported, not chosen after seeing the result. Ratio metrics with the member as randomisation unit also need delta-method or bootstrap variance, since numerator and denominator are correlated.
Randomising individual members when the treatment travels along the social graph
If treated members post, comment or share more, their followers see the extra content whether or not those followers are treated, so the control group is partly treated and the measured difference understates the true effect. For features that redistribute a fixed amount of attention, the leakage runs the other way and the effect is overstated. The size of the bias scales with how dense the neighbourhood is, so it is largest exactly among the connected members whose behaviour the feature was built for. The fix is randomising clusters of the graph (ego networks or communities found by balanced partitioning), clustering the variance at that unit, and accepting that effective sample size falls by roughly the average cluster size.
Extrapolating a first-week lift inflated by novelty effects
Plot the treatment effect by days since first exposure instead of quoting one pooled average. A lift that decays toward zero across the test window is behaviour that will not persist, and annualising it produces a forecast that misses by an order of magnitude.
Reading experiment results before checking the arm split
Compare observed arm counts against the intended allocation ratio, not an assumed even split, and set the alarm far below the conventional 0.05: at 0.05 roughly one healthy experiment in twenty trips it, which is why sample-ratio checks usually run at p < 0.001 or stricter. The test's power scales with sample size, so it misses a real diversion on a small experiment and fires on an imbalance too small to move the estimate on a very large one. A flag means go find the assignment or logging fault before reading any outcome, not report a mismatch.
Questions & practice
Roll a daily negative feedback rate up to a week
Easy · rate hygiene · groupby · denominators
You have two DataFrames. impressions: impression_id, event_date (date), surface. engagements: event_id, event_date, surface, impression_id (nullable), is_negative_feedback (bool). Compute negative feedback per 1,000 impressions: 1000 times the count of engagement rows with is_negative_feedback True and impression_id not null, over the count of impressions in the same date and surface. Return a daily table by surface, then a weekly table built by re-summing numerator and denominator. Also return the unweighted mean of the seven daily rates for the same weeks, and say which number you would publish.
Approach
- Aggregate the two frames separately to (event_date, surface) grain: a numerator count from engagements filtered on is_negative_feedback and impression_id.notna(), a denominator count from impressions. Keep them as two columns, not a pre-divided rate, because everything downstream needs the parts.
- Outer-join numerator onto denominator so that a day with impressions and zero negative feedback becomes a 0 rather than disappearing. A dropped zero-numerator day silently raises every rolled-up rate.
- Attach a week key to the daily frame, then compute the weekly rate as 1000 * sum(numerator) / sum(denominator) grouped by (week, surface). This is a ratio of sums.
- Compute the second, wrong number for comparison: groupby(week, surface).rate.mean(). Show the two side by side with the daily impression counts so the divergence has a visible cause.
- State the rule: the weighted version is the volume-weighted average of the daily rates, so the unweighted mean over-weights low-traffic days. The two agree only when every daily denominator is identical.
- Report numerator, denominator and rate in the output, never the rate alone, so a reader can tell a denominator move from a numerator move.
Follow-up
- The hide control moved from a submenu to the card on Tuesday. What happens to this metric, and is it a quality regression?
- How would you report this rate split by hide, report, not-interested and unfollow without publishing four charts nobody reads?
- An engagement row has impression_id NULL. Should it be in this numerator, and what is it measuring if you include it?
Classify daily actives into four mutually exclusive flow classes
Medium · dau decomposition · cohorts · local time
sessions has member_id, session_start_utc (datetime64[ns]) and is_qualified (bool); members has member_id and tz_offset_minutes. Using qualified sessions only, put every active (member, local_date) pair into exactly one class: new (first ever qualified session that day), retained (also active the previous local day), reactivated (not active the previous day but active at least once in days d minus 28 through d minus 2), resurrected (not active at all in d minus 28 through d minus 1, active before that). Return a daily table of the four counts plus DAU, and report churn separately.
Approach
- Derive local_date as (session_start_utc + tz_offset_minutes).dt.date after joining members. A UTC day boundary cuts an evening session in half for large parts of the world, which depresses the metric by geography alone and makes country cuts uninterpretable.
- Reduce to distinct (member_id, local_date) rows first. Multiple qualified sessions in one local day are one active day, and forgetting this inflates every class equally while leaving the sum check passing, so it is invisible.
- The whole classification collapses to one lag. Sort by (member_id, local_date), take prev = groupby(member_id).local_date.shift(1), and let gap = local_date minus prev in days.
- Map gap to class: prev is NaT gives new; gap == 1 gives retained; 2 <= gap <= 28 gives reactivated; gap > 28 gives resurrected. This is exactly equivalent to the written windows, because the previous active date being in [d-28, d-2] is the same statement as the member being inactive on d-1 and active somewhere in that window.
- Compute churn on day d as members active on d-1 and absent on d. It belongs in its own table: its denominator is yesterday's actives, not today's DAU, so putting it in the same frame invites someone to add five numbers that do not sum to anything.
- Name the left-censoring limit before being asked, and name its direction. prev is NaT for anyone whose prior activity predates the window, so new absorbs those members and is inflated, while resurrected needs an observed gap above 28 days and therefore cannot occur before the 30th date at all. Drop that burn-in or carry a first-ever-active date computed from a longer history, and do not read the burn-in shape as a product change.
Follow-up
- DAU is flat week over week but retained fell and reactivated rose by the same amount. What do you tell the product owner?
- Marketing turned on a paid campaign on Monday. Which of these four classes moves first, and how long before it shows up in the weekly active number?
- How would you extend this to say whether the reactivated members are the same people every week or a rotating set?
Write a data-quality audit over impression and engagement logs
Easy · data quality · referential integrity · null semantics
You are given impressions (impression_id, event_date, viewer_member_id, content_id, rank_position, dwell_ms, served_at_utc), engagements (event_id, actor_member_id, content_id, impression_id nullable, action_type, occurred_at_utc, undone_at_utc nullable) and content (content_id, author_member_id, created_at_utc, enforcement_state, enforcement_at_utc). Write audit(impressions, engagements, content) returning one row per check with the failing row count and share. Cover at least six checks across uniqueness, value range, referential integrity and timestamp ordering. Mark each check block-the-refresh or log-only, and say which NULLs are by design rather than defects.
Approach
- Group the checks by failure class first, then write one vectorised expression per check, so the function stays a table of (name, predicate) rather than a wall of conditionals. Every check returns a boolean mask over one frame and the report is built by summing masks.
- Uniqueness and range: duplicated impression_id; rank_position < 1; dwell_ms < 0 or null; served_at_utc in the future relative to the partition date.
- Referential integrity: engagement rows whose non-null impression_id is absent from impressions; impression rows whose content_id is absent from content. Then the sharper one, which is what catches real pipeline breaks: engagement rows joined to their impression where viewer_member_id does not equal actor_member_id, or the two content_id values disagree.
- Timestamp ordering: undone_at_utc earlier than occurred_at_utc; engagement occurred_at_utc earlier than its impression's served_at_utc; content created_at_utc later than an impression of it.
- Separate by-design NULLs from defects explicitly. impression_id is NULL for follow, unfollow and profile_click, and for any deep-linked action, so its null rate is a distribution to monitor, not a check to fail. session_id is NULL for server-side actions. duration_seconds is NULL for non-video media.
- Classify severity by what the number is used for: referential mismatches between actor and viewer corrupt every rate denominated in impressions and should block; a small orphan-FK share from late-arriving partitions is log-only with a threshold and a trend.
Worked solution (25 min)
- Define CHECKS as a list of (name, frame, mask_fn, severity) so the report loop is three lines and adding a check is one.
- Build the joined frame once: e2i = engagements[engagements.impression_id.notna()].merge(impressions, on='impression_id', how='left', suffixes=('_e','_i')), then derive the orphan mask from the null right-side key and the mismatch masks from the compared columns.
- Run every mask, collect (check, severity, n_failing, share, n_total) into a DataFrame, and sort by severity then share.
- Add a separate informational block reporting the null rate of impression_id split by action_type, which is the distribution that would reveal a client logging regression without any check failing.
Expected result: A DataFrame with one row per check giving check name, severity, failing rows, total rows and failing share, plus an informational table of impression_id null rate by action_type showing near 100 percent for follow, unfollow and profile_click and a low, stable rate elsewhere.
Verify it yourself
- Inject 10 known-bad rows of each kind into a copy of the input and confirm each check reports exactly 10.
- The total row count reported per check matches the frame that check runs over, so a share is never computed against the wrong denominator.
- On clean input every check reports zero except the informational null-rate block, which is not a check.
- The actor-versus-viewer mismatch check runs only over rows with a non-null impression_id, so it cannot be inflated by by-design NULLs.
Follow-up
- The orphan rate on engagement to impression is 0.4 percent and all of it is within two hours of the partition boundary. Block or log?
- enforcement_at_utc is later than impressions already served for that content. Is that a defect, and what does it do to a query you ran last week?
- How would you turn this audit into something that fails a pipeline rather than producing a report nobody opens?
How would you handle missing data when joining user profile tables with interaction logs?
Medium · sql and data manipulation
Approach
- Check whether any join is one-to-many before aggregating, or the sums inflate.
- Say which table is the grain you start from, and join outward from it.
- Handle the rows that do not match: a LEFT JOIN with a NULL check is usually the question.
Follow-up
- How does the query change if the join becomes one-to-many?
- What breaks if events arrive late or out of order?
Write a query using SQL window functions to calculate the running average of user interactions over the last 30 days.
Medium · sql and data manipulation
Approach
- Handle the rows that do not match: a LEFT JOIN with a NULL check is usually the question.
- Say which table is the grain you start from, and join outward from it.
- Compute rates by summing numerator and denominator separately, never by averaging rates.
Follow-up
- How does the query change if the join becomes one-to-many?
- How would you verify this result without re-running the same query?
Find original items that earned no engagement, correctly
Hard · null semantics · anti-join · as-of state
From fct_content_item(content_id, author_member_id, created_at_utc, item_kind, enforcement_state, deleted_by_author_at_utc) and fct_engagement_event(event_id, content_id, target_member_id, action_type, is_negative_feedback, occurred_at_utc), list original items published last week that received no engagement of any kind in their first 72 hours. Note that fct_engagement_event.content_id is NULL for the follow, unfollow and profile_click action types. Return content_id, author, created_at_utc and the item's impression count from fct_feed_impression. A colleague's version returns zero rows on this data; explain why before you fix it.
Approach
- Name the bug first. NOT IN against a subquery that yields even one NULL evaluates to UNKNOWN for every outer row, because NOT IN expands to a conjunction of inequality comparisons and any comparison with NULL is UNKNOWN. UNKNOWN is not TRUE, the WHERE clause admits nothing, and the result is empty rather than visibly wrong.
- Fix it with NOT EXISTS, or with a LEFT JOIN plus an IS NULL test on the joined key. NOT EXISTS is the better habit because it stays correct when a NULL appears in a column that had none when the query was written, which is the failure mode that reaches production.
- Put the 72-hour condition inside the NOT EXISTS correlation rather than in an outer WHERE. Filtering on the engagement timestamp after a LEFT JOIN converts the anti-join back into an inner join and quietly returns items that were engaged with, just later.
- Separate no engagement from no distribution by joining a pre-aggregated impression count. A zero-engagement item with 3 impressions is a ranking outcome; one with 5,000 impressions is a content outcome, and only the second is worth anyone's afternoon.
- Decide and state the as-of rule. enforcement_state and deleted_by_author_at_utc are mutable and enforcement_at_utc is always later than impressions already served, so an item demoted today reads as unengaging retroactively. Either pin the window to items whose enforcement postdates it, or carry enforcement_state as an output column and let the reader condition on it.
Worked solution (40 min)
- Reproduce and diagnose: SELECT COUNT(*) FROM fct_engagement_event WHERE content_id IS NULL returns a large positive number, since every follow, unfollow and profile_click row has no content.
- Rewrite as WHERE NOT EXISTS (SELECT 1 FROM fct_engagement_event e WHERE e.content_id = c.content_id AND e.occurred_at_utc < c.created_at_utc + INTERVAL '72 hours').
- Restrict the outer set to item_kind = 'original', created_at_utc inside last week, and created_at_utc + INTERVAL '72 hours' already elapsed, so every item in the result had its full observation window.
- LEFT JOIN a per-content_id impression count aggregated from fct_feed_impression and COALESCE it to 0.
- Carry enforcement_state through and count how many of the zero-engagement items are labelled, demoted or removed before drawing any conclusion about content quality.
Expected result: A non-empty list of original items with zero engagement in their first 72 hours, each carrying its impression count and enforcement state. The corrected query returns strictly more rows than the NOT IN version, which returns none, and most rows are low-impression items rather than well-distributed ones.
Verify it yourself
- The NOT IN version returns 0 rows while the NOT EXISTS version returns a positive count on identical data.
- Adding AND content_id IS NOT NULL inside the NOT IN subquery reproduces the NOT EXISTS row count exactly, which confirms NULL semantics was the whole bug.
- Joining the result back to fct_engagement_event finds no matching row inside any item's 72-hour window.
- Items whose 72-hour window has not yet closed are absent from the result rather than appearing as false positives.
Follow-up
- Write the anti-join three ways — NOT EXISTS, LEFT JOIN with IS NULL, and NOT IN with a NULL guard — and say which one you would put on a billion-row fact and why.
- Half the zero-engagement items have fewer than 20 impressions. What is the real finding, and what is the next cut?
- How would you make this query return the same number when someone re-runs it a month from now?
How would you define a "successful date" in the context of our product metrics?
Medium · product sense and metrics
Approach
- Restate the decision this analysis has to support, and who acts on the answer.
- Fix the population and the time window before naming any metric.
- State what result would change your recommendation, so the answer is falsifiable.
Follow-up
- Which segment would you cut first, and what would that rule out?
- How would you detect that the metric is being gamed rather than genuinely improving?
How do you balance the trade-off between short-term engagement and long-term user retention?
Medium · product sense and metrics
Approach
- Restate the decision this analysis has to support, and who acts on the answer.
- Name one primary metric, then the guardrail that stops it being gamed.
- State what result would change your recommendation, so the answer is falsifiable.
Follow-up
- How would you detect that the metric is being gamed rather than genuinely improving?
- What would you do if the primary metric and the guardrail moved in opposite directions?
How would you measure the success of a new feature designed to increase the number of "Likes" sent?
Medium · product sense and metrics
Approach
- Decompose the metric into the rates that drive it, and say which one you would check first.
- Restate the decision this analysis has to support, and who acts on the answer.
- Name one primary metric, then the guardrail that stops it being gamed.
Follow-up
- What would you do if the primary metric and the guardrail moved in opposite directions?
- How would you detect that the metric is being gamed rather than genuinely improving?
If you were launching a feature to reduce "ghosting," what metrics would you track?
Medium · product sense and metrics
Approach
- Decompose the metric into the rates that drive it, and say which one you would check first.
- Name one primary metric, then the guardrail that stops it being gamed.
- Restate the decision this analysis has to support, and who acts on the answer.
Follow-up
- Which segment would you cut first, and what would that rule out?
- How would you detect that the metric is being gamed rather than genuinely improving?
Explain the concept of statistical significance to a non-technical product manager.
Medium · a/b testing and experimentation
Approach
- Decide the analysis before seeing data, including how long it runs and when you look.
- Name the randomisation unit first; it decides the variance and what the test can detect.
- Say whether units interfere with each other, and switch design if they do.
Follow-up
- What would you conclude if the result is positive but the test is underpowered?
- What would you do if you could not randomise at all?
What are the most common experimentation pitfalls you have encountered in your career, and how do you avoid them?
Medium · a/b testing and experimentation
Approach
- Name the randomisation unit first; it decides the variance and what the test can detect.
- Decide the analysis before seeing data, including how long it runs and when you look.
- Say whether units interfere with each other, and switch design if they do.
Follow-up
- What would you conclude if the result is positive but the test is underpowered?
- What would you do if you could not randomise at all?
If we see a sudden drop in daily active users on a specific segment of our platform, how would you investigate the root cause?
Medium
Approach
- State your assumptions explicitly before working the problem.
- 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.
Follow-up
- How would you know your answer was wrong?
- What assumption would you test first?
Choose a randomisation unit when reposts travel along the graph
Medium · interference · cluster randomisation · design effect
A one-tap repost affordance is proposed for home_feed. Treated members are expected to repost more, and fct_follow_edge shows the median member follows 180 active accounts. A balanced partition of the active follow graph yields clusters averaging 40 members, with an intra-cluster correlation of 0.02 on the primary metric. Deliver the randomisation unit you would use, the sign of the bias if you randomise individual members instead, and the power cost of your design stated as a change in minimum detectable effect at fixed traffic.
Approach
- Name the leakage channel explicitly: the treatment output is content, and content reaches followers through fct_follow_edge regardless of the follower's arm. A control member who follows treated members receives part of the treatment, so the control mean rises and the measured difference understates the true effect.
- Say when the sign flips. For a feature that adds supply, interference attenuates the estimate toward zero. For a feature that reallocates a fixed number of slots, treated members win attention that control members lose, the control arm is pushed down, and the estimate is inflated.
- Randomise clusters of the graph: a balanced partition or ego-network design, assigned whole, so that most of a member's followees share their arm.
- Price the design: design effect = 1 + (m - 1) x rho with m = 40 and rho = 0.02. With unequal cluster sizes the cost is higher, approximately 1 + ((CV^2 + 1) x m - 1) x rho, and social graph partitions always have a heavy size tail.
- Estimate variance at the randomisation unit: cluster-level means weighted by size, or a member-level model with cluster-robust standard errors. With fewer than roughly 40 clusters per arm, fall back on CR2 with G - 1 degrees of freedom or randomisation inference.
- Report containment rather than assuming it: the share of each member's active followees that sit in the same cluster, plus an exposure-response cut on fraction of neighbours treated, which bounds the residual leakage the partition did not remove.
Worked solution (30 min)
- Compute the design effect: 1 + (40 - 1) x 0.02.
- Convert to an MDE multiplier by taking the square root, and to a sample multiplier directly.
- Apply it to an individually randomised baseline of 95,900 members per arm to get the members and clusters required.
- Write the analysis plan at cluster grain: one size-weighted mean per cluster, difference of arm means, variance across clusters.
- Add the containment diagnostic and the exposure-response cut as pre-registered secondary output.
Expected result: Design effect = 1 + 39 x 0.02 = 1.78. At fixed traffic the MDE grows by sqrt(1.78) = 1.33, so a 1.0 percent detectable effect becomes 1.33 percent. Holding the MDE fixed instead, you need 1.78 times the members: about 171,000 per arm, which is roughly 4,270 clusters of 40 per arm. Randomise clusters and accept that cost; individual randomisation here attenuates the estimate toward zero.
Verify it yourself
- Setting rho = 0 or m = 1 must return a design effect of exactly 1, which is the sanity check on the formula.
- The cluster-level analysis and a member-level regression with cluster-robust errors should return the same point estimate and similar intervals; a large gap means the weighting is inconsistent.
- The containment share should be well above 0.5 for the partition to be worth its power cost; if most followees sit outside the cluster, the design bought little.
- Recomputing the design effect with the observed cluster-size coefficient of variation should not move it by more than a few percent, or the balanced partition was not balanced.
Follow-up
- When would a switchback beat a cluster design here, and what property of the repost feature breaks a switchback?
- Your partitioner can only produce 30 clusters per arm. What changes in the analysis?
- How would you estimate the spillover effect itself rather than just eliminating it from the direct estimate?
Weekly active members fell 1.8 percent: find the flow
Easy · dau decomposition · segment cuts · data completeness
Weekly members with at least one qualified session fell from 12.40M to 12.18M week over week, a 1.8 percent drop. You have dim_member, fct_feed_impression, fct_engagement_event and fct_content_item. The release log shows nothing shipped that week. Produce an ordered diagnostic checklist and run it far enough to name which flow moved: new, retained, reactivated or resurrected. Deliverable is a one-page readout stating the flow, the segment carrying most of the absolute member delta, and the residual you could not explain.
Approach
- Confirm the number before explaining it. Check partition completeness for the last two event_date partitions in fct_feed_impression and fct_engagement_event against the trailing four-week median rows per hour, and check whether a metric-definition commit landed. A 1.8 percent move is well inside what one late or partial partition produces, and explaining an artefact is the most expensive failure mode here.
- Rule out the calendar before the product. Confirm both weeks have identical weekday composition, no holiday in either, and compare the same week in prior years rather than only against last week, since this metric has a weekly and an annual shape.
- Decompose into the four DAU flow classes (new, retained, reactivated, resurrected) for every day in both weeks and verify they sum exactly to DAU each day. Read which class moved: a fall in new is acquisition and cannot be a same-week product regression, a fall in retained is.
- Cut the moved class by client_platform, app_version, country_code, tenure bucket and acquisition_channel, one dimension at a time, and rank the cuts by absolute member delta rather than percentage. A 20 percent drop inside a segment holding 1 percent of members cannot produce a 1.8 percent platform move.
- Separate mix from rate: recompute the platform number holding the prior week's segment weights fixed. The difference between that and the actual move is the mix term, and it is a different product conversation from a within-segment decline.
- Write the readout as flow plus segment plus residual, and name the single query that would close the residual instead of asserting a cause you have not isolated.
Follow-up
- If the entire drop sits in the new class, how far back must the acquisition change have happened, and why is a same-week product explanation almost certainly wrong?
- A qualified session needs 30 or more foreground seconds. How would you check whether a client timing change altered how strict that threshold effectively is?
- What evidence would make you call this seasonal rather than a regression, and what would you tell the product owner in the meantime?
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.
Getting an analysis acted on
Work that nobody used is a common and unflattering pattern in data careers, and interviewers probe for it. Have a story about an analysis that changed a decision, and be specific about how you got it in front of the person who could act. Also have one about work that went nowhere, with your reading of why.
Describe a situation where you had to balance technical rigor with the need for speed in product development.
Medium · behavioural and stakeholder questions
Approach
- State the situation in two sentences and spend the rest on your reasoning.
- Close with what you would do differently, concretely.
- 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?
State the impact of your last six months without inflation
Medium · impact · counterfactual · attribution
Summarise your last two quarters in five minutes, with numbers. For each claim state the decision it changed, the counterfactual (what would have been decided without your work), how the effect was measured (randomised read, before-after, or estimate), and who else has to be credited. Rank the projects by realised impact, not effort, and name the one that produced nothing. Do not present a shipped feature as your impact unless you can say what would have shipped otherwise.
Approach
- Structure every claim the same way so the interviewer can compare them: decision changed, counterfactual, measurement method, shared credit. A list of projects without counterfactuals is a job description, not an impact statement.
- Separate the two kinds of impact an analyst actually has and price them differently instead of converting both into a revenue figure. Decisions changed (a launch held, a cap not raised, a metric redefined before it locked in) are one kind; capability added (a definition, a holdout, a pipeline that later decisions ran on) is the other and usually compounds harder.
- Label the measurement honestly per claim. A randomised read supports a causal number; a before-after during a season or a marketing push supports a bounded statement at best. Saying which is which before being asked is the fastest credibility signal available in this question.
- Discount shared attribution out loud. A launch carries engineering, design and product with it, so claim the part your analysis moved: the decision that would have gone the other way, or the magnitude that was wrong until you corrected it.
- Name the project that produced nothing and say when you should have stopped it. Then rank by realised impact and be ready for the ranking to put your largest effort in third place, which is the point of the exercise.
Follow-up
- Which of these would have happened without you, roughly on the same timeline?
- What did you stop working on, and what was the signal that made you stop?
- How would your manager order this list differently, and why?
Defend a qualified-session definition against two motivated objections
Hard · metric definition · gameability · north star
The north star is weekly members with at least one qualified session: 30 or more foreground seconds plus at least one non-negative engagement or authored item. A utility surface team argues the 30-second floor penalises fast successful visits. A video team argues requiring an explicit action undercounts passive watching. Both teams are reviewed on this metric. In fifteen minutes, defend or revise the definition, state what each proposed change does to gameability, and name the evidence that would justify a revision.
Approach
- Split the two objections, because they attack different clauses and fail differently. The utility objection is about a threshold (30 seconds); the video objection is about the qualifying condition (an explicit action). Answering both with the same argument is the common tell that the definition was never understood.
- Test each proposed change for gameability before discussing its merit. Dropping the action requirement makes the metric movable by autoplay, by longer video, and by any change that keeps an item in the viewport, which is precisely the failure the clause exists to prevent. A per-surface floor lets one team obtain a definitional lift without changing member outcomes, and makes the platform total a sum of incomparable parts.
- Answer the video objection with evidence rather than principle, and say what evidence would move you: compare week-1 retention among members whose only qualifying signal was long dwell on video_short impressions against members whose qualifying signal was an explicit action. If a fitted dwell threshold predicts return at the same rate as a like, a dwell-based qualifier is defensible, fitted per media_type and re-fitted per period rather than inherited.
- Answer the utility objection by separating the metric from the review. One definition platform-wide, with surface-level diagnostics beside it, and a review conversation that credits the utility surface on its own funnel rather than on a whole-platform north star it structurally cannot move. Forking the definition solves the review problem by destroying the metric.
- Fix the change process in advance so revisions cannot be mistaken for wins: any new definition is dual-reported beside the old one for at least four weeks, the size of the definitional jump is published, and the team proposing the change does not own the analysis that evaluates it.
Follow-up
- The utility team says they are graded on a number they cannot move. What do you actually offer them?
- What evidence would make you drop the 30-second floor entirely, rather than adjust it?
- Enforcement state changes after impressions are served. Does a session stay qualified when its only engagement was on content later removed?