Skip to content
Laviyx Learn

Try

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.

Advanced8 min readUpdated
On this page

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
Python
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))
Output
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.0

The 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
Python
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)
Output
  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        1

diff 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"), float32 where precision allows).
  • Parse dates once and drop intermediate columns.
Python
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")
Output
{'city': CategoricalDtype(categories=['Delhi', 'Mumbai', 'Pune'], ordered=False, categories_dtype=object), 'qty': dtype('int8')}
30.9x smaller

For 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.

Python
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))
Output
treatment     A    B
severity
mild       0.95  0.9
severe     0.70  0.6
treatment
A    0.75
B    0.84
dtype: float64

Treatment 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
  1. Check the data: is the drop real or a tracking/pipeline problem (missing events, a late data load, a changed definition)?
  2. Check the calendar: holidays, weekends, seasonality; compare with the same day last week and last year.
  3. 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.
  4. Check changes: releases, experiments, outages, marketing campaigns ending.
  5. 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?