Python for Data course menu
Advanced Data Analysis Interview Questions (pandas, Statistics, A/B Tests)
Advanced data analyst and data scientist interview questions: cohort retention in pandas, sessionising events, memory optimisation for large DataFrames, A/B test sample size and pitfalls, Simpson's paradox, and analysing a metric drop.
On this page
- pandas problems
- 1. Build a monthly cohort retention table.
- 2. Split user events into sessions (a new session after 30 minutes of inactivity).
- 3. A DataFrame uses too much memory. How do you reduce it?
- Statistics and experiments
- 4. Explain Simpson's paradox with an example.
- 5. How do you decide the sample size and duration of an A/B test?
- 6. Daily active users dropped 10% yesterday. How do you investigate?
- 7. Why might an A/B test result fail to replicate after launch?
- Key takeaway
Advanced rounds combine pandas skill with product and statistical judgement. Explain your reasoning as you go.
pandas problems#
1. Build a monthly cohort retention table.#
Each row is a user's order. A user's cohort is the month of their first order. Show, for each cohort, how many users ordered again 0, 1, 2 … months later.
Show solution
import pandas as pd
orders = pd.DataFrame({
"user": [1, 1, 1, 2, 2, 3, 3, 4, 4, 4],
"date": pd.to_datetime(["2026-01-03", "2026-02-10", "2026-03-15", "2026-01-20", "2026-03-02",
"2026-02-05", "2026-03-09", "2026-02-11", "2026-02-25", "2026-04-01"]),
})
orders["month"] = orders["date"].dt.to_period("M")
orders["cohort"] = orders.groupby("user")["month"].transform("min")
orders["months_since"] = (orders["month"] - orders["cohort"]).apply(lambda d: d.n)
retention = (orders.groupby(["cohort", "months_since"])["user"].nunique()
.unstack(fill_value=0))
print(retention)
print((retention.div(retention[0], axis=0) * 100).round(0))months_since 0 1 2
cohort
2026-01 2 1 2
2026-02 2 1 1
months_since 0 1 2
cohort
2026-01 100.0 50.0 100.0
2026-02 100.0 50.0 50.0The key steps: transform("min") gives each user's first month on every row, the difference between periods gives the age, and nunique counts active users per cohort and age. Dividing by month 0 gives retention percentages. Retention can rise again in a later month (the January cohort at month 2) because users who skipped a month came back.
2. Split user events into sessions (a new session after 30 minutes of inactivity).#
Show solution
import pandas as pd
events = pd.DataFrame({
"user": ["a", "a", "a", "b", "b", "a"],
"time": pd.to_datetime(["2026-05-01 10:00", "2026-05-01 10:10", "2026-05-01 11:00",
"2026-05-01 10:05", "2026-05-01 10:20", "2026-05-01 11:15"]),
}).sort_values(["user", "time"])
gap = events.groupby("user")["time"].diff()
events["new_session"] = gap.isna() | (gap > pd.Timedelta(minutes=30))
events["session"] = events.groupby("user")["new_session"].cumsum()
print(events) user time new_session session
0 a 2026-05-01 10:00:00 True 1
1 a 2026-05-01 10:10:00 False 1
2 a 2026-05-01 11:00:00 True 2
5 a 2026-05-01 11:15:00 False 2
3 b 2026-05-01 10:05:00 True 1
4 b 2026-05-01 10:20:00 False 1diff within each user finds the gaps; a cumulative sum of the "new session" flags numbers the sessions. User "a" starts a new session at 11:00 after a 50-minute gap.
3. A DataFrame uses too much memory. How do you reduce it?#
Show solution
- Load only the columns you need (
usecols) and process big files in chunks (chunksize). - Convert low-cardinality text columns to
category. - Downcast numbers (
pd.to_numeric(col, downcast="integer"),float32where precision allows). - Parse dates once and drop intermediate columns.
import numpy as np
import pandas as pd
df = pd.DataFrame({
"city": np.random.default_rng(0).choice(["Mumbai", "Delhi", "Pune"], 100_000),
"qty": np.random.default_rng(1).integers(1, 10, 100_000),
})
before = df.memory_usage(deep=True).sum()
df["city"] = df["city"].astype("category")
df["qty"] = pd.to_numeric(df["qty"], downcast="integer")
after = df.memory_usage(deep=True).sum()
print(df.dtypes.to_dict())
print(f"{before / after:.1f}x smaller"){'city': CategoricalDtype(categories=['Delhi', 'Mumbai', 'Pune'], ordered=False, categories_dtype=object), 'qty': dtype('int8')}
30.9x smallerFor data that still does not fit, move to a database (SQL) or tools built for larger-than-memory data.
Statistics and experiments#
4. Explain Simpson's paradox with an example.#
Show solution
A trend that appears in every group can reverse when the groups are combined, because the groups have different sizes or mixes.
import pandas as pd
df = pd.DataFrame({
"treatment": ["A", "A", "B", "B"],
"severity": ["mild", "severe", "mild", "severe"],
"patients": [100, 400, 400, 100],
"recovered": [95, 280, 360, 60],
})
df["rate"] = df["recovered"] / df["patients"]
print(df.pivot(index="severity", columns="treatment", values="rate").round(2))
overall = df.groupby("treatment")[["recovered", "patients"]].sum()
print((overall["recovered"] / overall["patients"]).round(2))treatment A B
severity
mild 0.95 0.9
severe 0.70 0.6
treatment
A 0.75
B 0.84
dtype: float64Treatment A has the better recovery rate for both mild and severe patients, yet B looks better overall, because A was given mostly to severe cases. The fix is to compare within groups (or adjust for the confounder), not on the pooled totals.
5. How do you decide the sample size and duration of an A/B test?#
Show solution
Choose the baseline rate, the minimum detectable effect worth acting on, α (usually 0.05) and power (usually 0.8), then compute the users needed per group with a power calculation. Divide by daily traffic to get the duration, and run at least one full weekly cycle. Smaller effects need many more users (halving the effect roughly quadruples the sample). Decide all of this before starting and do not stop early when the result first looks significant.
6. Daily active users dropped 10% yesterday. How do you investigate?#
Show solution
- Check the data: is the drop real or a tracking/pipeline problem (missing events, a late data load, a changed definition)?
- Check the calendar: holidays, weekends, seasonality; compare with the same day last week and last year.
- Segment: platform (iOS/Android/web), app version, country, new vs returning users, acquisition channel. A drop concentrated in one segment (for example one app version) points to the cause.
- Check changes: releases, experiments, outages, marketing campaigns ending.
- Quantify and communicate what you found, how confident you are, and what to monitor next.
7. Why might an A/B test result fail to replicate after launch?#
Show solution
Novelty effects wearing off, a false positive (5% of tests at α = 0.05 even with no real effect, more if results were peeked at), a test population that differs from the full population, interactions with other changes launched later, or seasonality during the test window.
Key takeaway#
More practice: the data analysis practice sets and interview questions.
Finished this lesson?