A Data Scientist at Reddit sits at the intersection of product innovation, community health, and massive-scale data analytics. With hundreds of millions of active users generating billions of posts, comments, upvotes, and search queries, Reddit represents one of the most complex, unstructured social graphs in the world. As a Data Scientist, your primary mission is to translate this vast ocean of user-generated content and interaction data into actionable insights that shape product roadmaps, optimize user engagement, and drive strategic business decisions.
In this role, you will work closely with cross-functional partners, including Product Managers, Software Engineers, and Designers, to influence key product areas such as the Home Feed, Subreddit Recommendations, Ads Optimization, Search Relevance, and Video Analytics. You will not merely build dashboards or run ad-hoc queries; you will design rigorous online experiments, develop sophisticated causal inference frameworks, and define the core metrics that measure the health and growth of Reddit's diverse communities.
The work of a Data Scientist at Reddit has a direct, visible impact on how millions of users discover and participate in communities. Whether you are analyzing user retention patterns, optimizing feed-ranking algorithms, or evaluating the safety and moderation tools that protect communities, your analytical rigor ensures that Reddit remains a vibrant and safe place for open, authentic human connection.
Recruiter Phone Screen
reportedData Scientist covers at least four different jobs: experimentation, product analytics, causal work on observational data, and applied modelling that ships into a system. A screening call is the cheapest place to find out which of them is being hired for, and doing that diagnosis openly reads as senior rather than fussy. Ask what the last few pieces of work on the team actually were, and roughly how a week splits between querying, modelling and stakeholder time. Then say which parts of that you have done and which you have not. Claiming the whole range is the fastest way to be caught one round later.
What to demonstrate
- Whether you can distinguish the flavours of the role and locate your own experience inside one of them honestly
- Whether you name what you have not done instead of stretching to cover every line of the posting
- Whether your hard constraints (notice period, location, work authorisation, level) surface now rather than at offer stage
How to prepare
- Map the last two years of your time into rough percentages across query writing, experiment design, modelling and stakeholder work, so a question about scope has a real answer
- Mark every responsibility in the posting as done, adjacent or new, and prepare one sentence for each adjacent item naming the closest thing you have actually built
- Decide which logistics are non-negotiable before the call so you can state them in one sentence rather than negotiating live
Hiring Manager Interview
reportedExpect a live problem with pieces of it missing, closer to a conversation than an exam. A metric moved, or somebody wants to know whether a change worked, and you are asked how you would find out. The manager is watching the first ninety seconds, specifically whether you establish what decision hangs on the answer before you start proposing methods. Candidates who open with a technique get steered back. Once the decision is clear, describe what the data would look like if the story were true, and say what you would accept as evidence that it is not.
What to demonstrate
- Whether you fix the decision the analysis serves before choosing an approach
- How you continue when you are told the data you just asked for does not exist
- Whether you state what would change your mind, not only what would confirm the hypothesis you started with
- How you size an effect before you have measured it
How to prepare
- Take a metric you know well and practise explaining in under two minutes the four things that could have moved it and how you would separate them
- Pick a recent launch or experiment and write the single number you would ask for first, plus what you would conclude if it came back flat
- Practise being interrupted: have someone remove a data source halfway through your answer and carry on without restarting
Technical Screen
reportedThis 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
Virtual Onsite Panel
reportedWhere 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
8 candidate reports. Individual accounts describe a particular role and hiring cycle.
Reddit Software Engineer Interview Experience — A Word-Search Rule Clarified Too Late
The author reports an unsuccessful Reddit coding screen involving word search. After presenting the task, the interviewer remained quiet while the applicant worked. The author did not confirm the movement rules and implemented a more permissive search than the interviewer expected. A typo also consumed about ten minutes. Although the applicant’s own tests passed, the interviewer said near the end…
Read full experienceReddit Machine Learning Engineer Interview Experience — General Pooling and a Ranking Interview
I applied to a particular team while sending out lots of applications online. The first phone screen was a question from the forum: analyze a spent-hours dataset and predict clicks. Since I had prepared it, the interview went quite smoothly. A week after the interview, I still hadn't heard anything, so I logged into the candidate portal. The position I had applied for was gone, and the interview…
Read full experienceReddit Machine Learning Engineer interview experience: two DSA rounds
The interview was straightforward: two data-structures-and-algorithms rounds along with machine-learning knowledge. The interviewers were kind and easygoing, and one of them in particular made the conversation feel comfortable. The format matched what I expected for the role. There were no strange surprises, just a clean sequence with a relaxed tone. I did not receive an offer, but the interview…
Read full experienceReddit Backend Engineer Interview Experience — Load Balancer Deep-Dive and a One-Week Offer
General coding 1: the Report Chain problem General coding 2: the Tennis Game problem — afterward the interviewer also chatted with me a bit about the strategy pattern Backend programming: the Load Balancer problem: It's split into four parts, and they give you a codebase. Part 1: The load balancer keeps getting error code 500. You need to find the cause — the cause is that the LB has the hostname…
Read full experienceReddit Machine Learning Engineer Interview Experience — Tennis Scoring OOD With Sets and Side Switching
View report detailsPracHub editorial advice for the preparation topics above.
Crediting notifications with the sessions that follow them
Members who open a push notification were already more likely to open the app, so attributing their session to the notification measures intent rather than causation and makes almost any send look profitable. The predictable result is a push-volume increase that shows a large modelled gain and a small real one, paid for later in opt-outs and uninstalls that no single experiment window captures. The only defensible estimate compares a stable send arm against a holdout arm assigned at the decision point, with the held-out decisions logged and suppressed at delivery, over a window long enough to include the opt-out response. Frequency effects are non-linear, so a per-notification incremental rate estimated at one volume does not extrapolate to a higher one.
Reading engagement rates off impressions the ranker chose to serve
Engagement per impression by content type, author or topic is conditioned on the ranker's selection, and the ranker selected precisely what it predicted would be engaged with. A content type with a high observed engagement rate may simply be one the ranker only shows in easy contexts, and a type with a low rate may be one it shows indiscriminately. The same logic makes rank position a confounder: slot 1 outperforms slot 20 for reasons that have nothing to do with the item. Any counterfactual claim from this data needs either logged, strictly positive propensities and an inverse-propensity or doubly-robust estimator, or a randomised exploration slot. Where log_propensity is NULL because serving was deterministic top-k, no reweighting recovers the answer and an online test is the only option.
Analysing at a different unit than the one randomised
Say out loud what was randomised (user, device, account, cluster) and make the analysis unit match, or account for the clustering with cluster-robust standard errors, the delta method, or aggregation up to the randomised unit. Randomising users and then running a test over sessions understates variance and inflates the false-positive rate.
Naming a model class before naming the deployment constraints
Set out the latency budget, the label delay, the retraining cadence, the interpretability requirement and the number of labelled examples, then pick the model that fits them. A boosted-tree answer to a problem where each decision must be explained to the affected user is a well-executed answer to the wrong question.
Choose a category, try a prompt, then open its approach, worked solution or follow-up when you need it.
If a new recommendation algorithm increases subreddit subscriptions bu…
If a new recommendation algorithm increases subreddit subscriptions but decreases overall time spent on the platform, how would you evaluate whether to launch it?
Approach
- Pick an evaluation metric that matches the cost of each error type, not a default.
- Set a baseline first, so any model has something honest to beat.
- Check what information would not exist at prediction time, and exclude it.
Follow-up
- What would you monitor after launch to know the model is still valid?
- Where could label leakage enter this setup?
Off-policy estimate with a positivity and weight audit
logged has impression_id, rank_position, reward (1 if the viewer engaged), log_propensity (float, NULL where serving was deterministic top-k) and target_propensity (the candidate policy's probability of placing the same item in the same slot, precomputed). Estimate the candidate policy's engagement rate per impression with inverse propensity scoring and with self-normalised IPS. Report the effective sample size as the square of the sum of weights over the sum of squared weights, the 99th percentile weight, the share of rows excluded for NULL or near-zero propensity, and the estimate under weight clipping at 20. State precisely what population your number describes.
Approach
- Audit before estimating. Split the rows into three buckets: usable (log_propensity strictly positive and recorded), NULL propensity, and positive but below a floor you choose and state. The NULL rows come from deterministic top-k serving, where no reweighting identifies the counterfactual, so they are not a data gap to impute; they are outside what this method can answer.
- Compute w = target_propensity / log_propensity on the usable rows. IPS is the mean of w * reward. It is unbiased under positivity and no unobserved confounding, and it has the variance problem that makes the rest of this exercise necessary.
- Compute SNIPS as sum(w * reward) / sum(w). It carries a small bias that vanishes with sample size, it is bounded inside the reward range so it cannot return an engagement rate above 1, and it is usually the number you would report.
- Report the effective sample size (sum w)^2 / sum(w^2) next to n. It is the honest denominator: 400,000 rows with ESS 3,100 is a 3,100-row estimate, and quoting the raw n next to a confidence interval derived from these weights is the way this analysis misleads people.
- Clip weights at the stated threshold, recompute, and describe the trade in the right direction: clipping caps variance and introduces downward bias wherever the target policy wants to act in regions the logging policy rarely visited, which is exactly where the candidate ranker differs most.
- State the estimand explicitly. After excluding the NULL and sub-floor rows, the number describes the sub-population of impressions where the logging policy explored, which is not the surface as a whole, and the decision that follows is whether to run an online test or add randomised exploration slots.
Follow-up
- Sixty percent of rows have NULL log_propensity. What do you change about the serving system to make this analysis possible next quarter, and what does it cost?
- Add a doubly-robust estimator on top of this. What does the reward model buy you, and what happens when it is wrong?
- The offline estimate says plus 4 percent and the online test comes back flat. Give two mechanisms that produce exactly that pattern.
Roll a daily negative feedback rate up to a week
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.
Worked solution 20 min
- num = engagements[engagements.is_negative_feedback & engagements.impression_id.notna()].groupby(['event_date','surface']).size().rename('neg')
- den = impressions.groupby(['event_date','surface']).size().rename('imps'); daily = den.to_frame().join(num, how='left').fillna({'neg': 0})
- daily['rate_per_1k'] = 1000 * daily.neg / daily.imps
- weekly = daily.groupby([week_key, 'surface'])[['neg','imps']].sum(); weekly['rate_per_1k'] = 1000 * weekly.neg / weekly.imps
- naive = daily.groupby([week_key,'surface']).rate_per_1k.mean(); join the two and print the gap alongside the daily impression counts
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?
Given a table of user registrations and a table of user logins, write …
Given a table of user registrations and a table of user logins, write a query to calculate the 7-day and 30-day retention rates for new users.
Approach
- 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.
- State the window function and its partition and ordering out loud before writing it.
Follow-up
- How would you verify this result without re-running the same query?
- What breaks if events arrive late or out of order?
Given a schema containing user activity logs, write a query to calcula…
Given a schema containing user activity logs, write a query to calculate the daily active users (DAU) who have upvoted posts in more than three distinct subreddits.
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.
- State the window function and its partition and ordering out loud before writing it.
Follow-up
- How does the query change if the join becomes one-to-many?
- What breaks if events arrive late or out of order?
Find original items that earned no engagement, correctly
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.
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?
What metrics would you track to determine if a community is "healthy" …
What metrics would you track to determine if a community is "healthy" and growing sustainably?
Approach
- Fix the population and the time window before naming any metric.
- 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?
A product manager wants to add a new "share" button to posts. What cor…
A product manager wants to add a new "share" button to posts. What core and guardrail metrics would you establish before launching this feature?
Approach
- Decompose the metric into the rates that drive it, and say which one you would check first.
- Fix the population and the time window before naming any metric.
- 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?
Given a list of dictionaries representing subreddit metadata, write a …
Given a list of dictionaries representing subreddit metadata, write a script to filter, aggregate, and sort the data based on specific engagement thresholds.
Approach
- Fix the population and the time window before naming any metric.
- 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?
How would you measure the impact of search relevance improvements on u…
How would you measure the impact of search relevance improvements on user retention?
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.
- Decompose the metric into the rates that drive it, and say which one you would check first.
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?
Describe a situation where you would use causal inference methods (suc…
Describe a situation where you would use causal inference methods (such as propensity score matching or difference-in-differences) instead of standard A/B testing.
Approach
- Decide the analysis before seeing data, including how long it runs and when you look.
- State the primary metric and the minimum effect worth shipping, then size the test.
- Name the guardrails that would stop a launch even on a positive primary result.
Follow-up
- What would you do if you could not randomise at all?
- What would you conclude if the result is positive but the test is underpowered?
What statistical techniques would you use to analyze an experiment if …
What statistical techniques would you use to analyze an experiment if you cannot run a randomized controlled trial and must rely on observational data?
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.
- State the primary metric and the minimum effect worth shipping, then size the test.
Follow-up
- How would you handle interference between treated and control units?
- What would you conclude if the result is positive but the test is underpowered?
Measure violating content prevalence when reports are the wrong instrument
Leadership tracks content quality with weekly report volume, counted from fct_engagement_event where action_type = 'report'. It fell 14 percent after a ranker release and the release was declared safe. Explain in mechanism terms why that inference is invalid, then specify the measurement you would build: the sampling frame over fct_feed_impression, the selection probabilities, the estimator, and the sample size needed to separate 0.50 percent from 0.60 percent prevalence at 80 percent power and 5 percent two-sided alpha. State what the resulting estimate still cannot tell you. Deliverable: critique, design with numbers, limitation.
Approach
- Give the mechanism for the fall rather than calling it suspicious. Reporting is a viewer behaviour, so a ranker that matches violating content more precisely to receptive audiences lowers reports and raises harm at the same time. Report counts also move with where the control sits in the UI and with coordinated campaigns, neither of which is a property of the content.
- Set the frame as served impressions, not content items, because harm scales with delivery. An item seen once and an item seen a million times are one row each in fct_content_item and wildly different in fct_feed_impression.
- Specify sampling with recorded, strictly positive probabilities: stratify by surface and language_code, record p_i per stratum, allow no stratum at zero. Then estimate prevalence as the ratio of sum(1/p_i) over sampled impressions labelled violating to sum(1/p_i) over all labelled impressions, with a ratio-estimator interval rather than a binomial one, because the denominator is itself a weighted sum.
- Do the arithmetic. For two proportions with p1 = 0.005 and p2 = 0.006, n per arm is approximately (1.96 * sqrt(2 * 0.0055 * 0.9945) + 0.8416 * sqrt(0.0050.995 + 0.0060.994))^2 / (0.001)^2, which is about 86,000 labelled impressions per arm. Inflate by the design effect implied by the variation in sampling weights, roughly 1 plus the squared coefficient of variation of those weights.
- State the limitation: the estimate is bound to one written policy version and carries label noise, it says nothing about harm from content that is within policy, and it cannot be compared against any figure derived from a report-based or classifier-tail sample.
Worked solution 40 min
- Write the report-volume critique as three named mechanisms, audience selection, control placement and coordinated campaigns, each with the direction it pushes the number.
- Define the frame and stratification: served impressions in the calendar week, stratified by surface and language_code, with p_i recorded per stratum and no stratum at zero.
- Write the Horvitz-Thompson ratio estimator and the form of its variance, and state that the confidence interval must be a ratio-estimator interval.
- Do the sample-size arithmetic for 0.005 against 0.006 and report the per-arm figure, then inflate it by the design effect from weight variation.
- Write the limitation paragraph and name the one change that makes the series comparable across quarters: attaching the frozen policy version to every label.
Follow-up
- Human labelling costs money. Given a fixed weekly budget, do you buy one large weekly estimate or a smaller daily one?
- The written policy changes mid-quarter. What happens to your series and what do you do about it?
- How would you measure the effect of a demotion, which changes distribution rather than removing the item?
Weekly active members fell 1.8 percent: find the flow
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?
For someone who can already write the query and train the model but stalls when asked what to measure or whether a change is worth making. Metric definition and case structure come first; the technical work is kept as maintenance rather than the centre of the week.
Prepare, practise & reflect
One practical outcome each day. Spend longer where you need it.
0 / 7 done01Metric anatomy
- For three products you use daily, write one primary metric, two input metrics that plausibly move it, and one guardrail that would catch a cheap way of moving the primary at the cost of the product.
- For one of them, specify the metric precisely enough that two analysts would return the same number: numerator, denominator, unit of observation, time window, and how returning and deleted accounts are treated.
- Pick a ratio metric and write what happens to it when the denominator shrinks for reasons unrelated to the numerator, with a concrete example of that happening.
Deliverable: A one-page metric tree for one product, with the primary metric written as an unambiguous spec.
Practice prompt ↗Practice prompt ↗Practice prompt ↗Worked solution ↗02Diagnosing a drop without guessing
- Take the prompt "weekly active users fell 8 percent week over week" and write the segmentation plan before proposing any cause: platform, region, tenure cohort, acquisition channel, and whether the movement sits in the numerator or in a changed denominator.
- List the instrumentation failures that manufacture fake drops (a client release that stopped firing an event, a bot filter change, a shifted date boundary or timezone) and write the query that rules out each one.
- Rehearse stating the boring explanations first, seasonality and day-of-week composition, before reaching for a product cause.
Deliverable: A drop-diagnosis checklist short enough to recite from memory in under a minute.
Practice prompt ↗Practice prompt ↗Practice prompt ↗03Should we build it
- Take a feature idea and write it as a bet: what you believe is true, what would have to be true for it to pay off, the metric that would confirm it, and the effect size that would justify the engineering cost.
- Size the opportunity top-down and bottom-up, then reconcile the two numbers in writing instead of quoting whichever is friendlier.
- Write the counter-metric that would make you kill the feature even if it wins on the primary metric.
Deliverable: A one-page product memo ending in a decision rather than a list of considerations.
Practice prompt ↗Practice prompt ↗Practice prompt ↗04The places aggregate numbers lie
- Construct a Simpson's paradox numerically: two segments where the treatment wins within each segment yet loses overall, and identify the shift in segment weights that causes it.
- Take a heavy right-tailed quantity such as revenue per user and write why the mean is the wrong summary, which percentile you would report instead, and what a moving mean with a stable median tells you.
- Write your definition of a session for the product from day one, then name two real behaviours it misclassifies.
Deliverable: One page holding a worked Simpson's paradox table and a session definition with its two known failure cases.
Practice prompt ↗Practice prompt ↗Worked solution ↗05Technical maintenance, aimed at metrics
- Solve four timed SQL prompts that all end in a ratio metric, so the question of grain stays live in every answer.
- Compute a 95 percent confidence interval for a proportion on a small sample, and state why the normal approximation is unreliable when either np or n(1 minus p) falls below roughly 10, along with which interval you would use instead.
- Take one metric from your day-one tree, write the query that computes it correctly, then write the query that computes it wrong in the most plausible way and explain how you would notice.
Deliverable: Four solved prompts plus a matched correct and plausible-wrong query for one metric.
Practice prompt ↗Practice prompt ↗06Turning engineering work into data science stories
- Write three project stories as situation, decision, trade-off, outcome, each carrying one number and one thing you got wrong.
- For the story you will lead with, prepare an answer to "what would you do differently" that names a decision you made, not a constraint you were handed.
- Practise the sentence that reframes a systems project as a question project: the question the work answered, ahead of the pipeline it shipped.
Deliverable: Three written stories with the lead story delivered aloud and timed under four minutes.
Practice prompt ↗Practice prompt ↗07Mock case and gap list
- Run a 40-minute mock case with someone playing a product manager who pushes back on your metric choice, and record it.
- Listen back and mark every moment you proposed a solution before the success metric existed.
- Rewrite those moments as the question you should have asked, and rehearse the first 90 seconds of the case until scoping comes before solving.
Deliverable: A recorded case plus a rewritten opening 90 seconds.
Practice prompt ↗Practice prompt ↗Worked solution ↗Expand any day for tasks and deliverables. Your progress is saved on this device.
Sometimes the honest read is that the initiative did not work, and the person who commissioned the analysis was hoping otherwise. Interviewers want to know whether you softened it. Prepare the case where you delivered an unwelcome result, how you presented the uncertainty without hiding behind it, and what the team did next.
Choose between three requests with one analyst week
You have one analyst week and three open requests. Ranking wants an off-policy estimate of a candidate ranker, but log_propensity is NULL on 92 percent of home-feed impressions. Growth wants a week-1 retention read on a registration cohort whose day 7 to 13 window closes in four days. Integrity wants the audit sample re-sized because the prevalence interval cannot detect a 20 percent change. Give the order, what each requester gets and when, and the request you refuse outright with the reason.
Approach
- Sort by identification before sorting by importance. A request that cannot be answered correctly with any amount of effort is not competing for the week; it is competing for a different conversation.
- Rule out the off-policy estimate on positivity grounds and say it in one line: log_propensity NULL means serving was deterministic top-k, so the unserved slots had zero logging probability, and no inverse-propensity or doubly-robust estimator is identified there. The fix is a randomised exploration slot or an online test, which is a platform change and not an analyst task.
- Rule out the retention read on timing: days 7 to 13 must have closed for every member in the cohort. Reading it four days early truncates the window for the late-registering half of the cohort and biases the estimate by registration day, which correlates with acquisition channel.
- Do the integrity re-size, because it is tractable in hours and unblocks a standing measurement. At a two-sided alpha of 0.05 and 80 percent power, detecting a move from 0.50 percent to 0.40 percent needs roughly 70,000 labelled impressions per comparison period under simple random sampling, before any design effect from unequal weights. That number reframes the request: the honest deliverable may be a stratified design plus a longer comparison window, not a bigger weekly sample.
- Convert each refusal into a dated deliverable so the week does not end in three unhappy teams: ranking gets the exploration-slot design and the randomised fraction it needs; growth gets the date the cohort closes plus the activation rate on days 0 to 6, which is already readable and is a leading indicator of the number they want.
Follow-up
- Ranking says a biased estimate is better than none. Answer them in two sentences.
- How large an exploration fraction would you request, and what does it cost in served quality?
- If integrity cannot fund 70,000 labels a week, what do you offer instead?
Defend a qualified-session definition against two motivated objections
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?
Scope a one-line request to measure notification value
A director messages: 'Are push notifications worth it? Get me a number by Thursday.' You have fct_notification_decision (decision, holdout_group, suppression_reason, notification_type, sent_at_utc, opened_at_utc, resulting_session_id), plus session and impression logs. Before writing any SQL, produce a one-page scoping note: the decision the number feeds, the exact estimand with its window and population, what you will not answer and why, and the single clarifying question you send back. Assume you get one reply, so choose the question that most changes the work.
Approach
- Start from the decision, not the data. 'Worth it' means a different estimand depending on whether the director is deciding a frequency cap, a channel investment, or whether to keep the notification platform team staffed. The first needs a marginal increment at a specific volume; the last needs a total increment against zero sends.
- Write the estimand as one sentence with all four parts fixed: incremental qualified sessions per member over 28 days, computed as the send arm minus the holdout_global arm, divided by sent notifications per member in the send arm, with holdout_group assignment stable for the whole window.
- Check identification before promising anything. Held-out decisions must be written at the decision point and suppressed at delivery. If the pipeline only writes rows for sends, the holdout arm is not observable in fct_notification_decision, nothing is identified, and Thursday's honest deliverable is the gap plus the instrumentation fix.
- Fix the population explicitly: which channels, whether notification_type = 'integrity' is in scope (it should not be, since it is not discretionary and is not traded off against anything), and whether members whose holdout_group changed mid-window are excluded (they are, and you report how many).
- State the two questions you are not answering, so they cannot be read into the number later: per-notification value at a higher cap, because frequency response is non-linear, and opt-out or uninstall cost, which needs a window longer than 28 days. Send back one question: which decision this feeds.
Follow-up
- There is no global holdout, only a per-type holdout. What can you still estimate, and what becomes unidentified?
- The holdout is 0.5 percent of members. What is your minimum detectable effect, and do you say so before or after running it?
- How would you surface opt-out risk in a 28-day read without waiting a quarter?
- 01
You have one analyst week and three open requests. Ranking wants an off-policy estimate of a candidate ranker, but log_propensity is NULL on 92 percent of home-feed impressions. Growth wants a week-1 retention read on a registration cohort whose day 7 to 13 window closes in four days. Integrity wants the audit sample re-sized because the prevalence interval cannot detect a 20 percent change. Give the order, what each requester gets and when, and the request you refuse outright with the reason.
- 02
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.
- 03
A director messages: 'Are push notifications worth it? Get me a number by Thursday.' You have fct_notification_decision (decision, holdout_group, suppression_reason, notification_type, sent_at_utc, opened_at_utc, resulting_session_id), plus session and impression logs. Before writing any SQL, produce a one-page scoping note: the decision the number feeds, the exact estimand with its window and population, what you will not answer and why, and the single clarifying question you send back. Assume you get one reply, so choose the question that most changes the work.
Is this an official Reddit interview guide?
No. It is PracHub's own research and practice material for the Data Scientist role at Reddit. Rounds and questions reflect what candidates have reported, not a process Reddit has published, and they change over time. Confirm the current format and scope with your recruiter.
PracHub interview research ↗How technical is the coding portion of the Reddit Data Scientist interview?
The technical coding rounds focus heavily on SQL fluency and basic Python data manipulation. For SQL, expect to write complex queries involving window functions and joins under time pressure. For Python, the focus is on array manipulation, basic data structures, and simple algorithms (such as finding the median of an array) rather than advanced Leetcode-style dynamic programming.
PracHub interview research ↗Does Reddit have different tracks for Data Scientists?
Yes. Reddit has multiple data science tracks, typically separating product analytics roles from machine learning and algorithmic roles. It is highly recommended to clarify with your recruiter early in the process which track you are being considered for, as this will dictate the focus and difficulty of your technical rounds.
PracHub interview research ↗How important is causal inference in the interview process?
Very important, especially for product analytics roles. Several candidates have reported being asked specific questions about causal inference, observational data analysis, and how to establish causality when standard A/B testing is not feasible. Having a solid grasp of these concepts can be a major differentiator.
PracHub interview research ↗What is the typical timeline for the interview process?
The process is generally quick and responsive, often taking 3 to 5 weeks from the initial recruiter call to the final decision. However, candidate experiences vary, and maintaining active communication with your recruiter is key to managing your timeline.
PracHub interview research ↗Sources & methodology 3 sources ↗
Official role evidence, timestamped platform data and clearly labeled preparation advice.
- 01PracHub interview research ↗
PracHub editorial research into this company and role, maintained with this guide. Candidate-reported, not an employer publication.
platform · Accessed 2026-09-22 - 02PracHub Data Scientist practice ↗
Cross-company practice questions for this role.
platform · Accessed 2026-09-22 - 03PracHub interview preparation framework ↗
The framework the preparation plan follows.
platform · Accessed 2026-09-22