Data science interviews test statistics, Python, machine learning intuition, business thinking, and communication skills. This guide covers the 50 most asked questions — with concise answers, code examples, and real interview scenarios.
Quick reference
| Topic | Most asked questions |
|---|---|
| Statistics & probability | Distributions, hypothesis testing, p-values, Bayesian |
| Python & pandas | Data manipulation, aggregation, merging, cleaning |
| EDA & visualisation | Missing values, outliers, distributions, charts |
| Feature engineering | Encoding, scaling, selection, creation |
| Model evaluation | Precision/recall, AUC, cross-validation, metrics choice |
| ML fundamentals | Bias-variance, overfitting, algorithms, ensembles |
| A/B testing | Design, sample size, significance, pitfalls |
| SQL for data science | Window functions, aggregations, cohorts |
| Business acumen | Metric drops, case studies, stakeholder comms |
| Practical scenarios | End-to-end project, product metric, churn |
Statistics & Probability
1. What is the difference between the mean, median, and mode? When do you use each?
| Measure | Definition | Best when |
|---|---|---|
| Mean | Sum ÷ count | Symmetric distributions, no outliers |
| Median | Middle value | Skewed distributions, outliers present |
| Mode | Most frequent value | Categorical data, finding peaks |
Real example: Household income is right-skewed (a few billionaires inflate the mean). Median income better represents the typical household. House prices use median for the same reason.
2. Explain the Central Limit Theorem and why it matters.
CLT: The distribution of sample means approaches a normal distribution as sample size increases — regardless of the population distribution — given samples are independent and n ≥ 30 (rough rule of thumb).
Why it matters for data science:
- Justifies using normal-based hypothesis tests (t-tests, z-tests) on non-normal data
- Underpins A/B testing frameworks
- Means confidence intervals and p-values work even when the underlying metric (revenue, session length) is skewed
- Explains why bootstrap sampling works
3. What is a p-value? What does p < 0.05 actually mean?
A p-value is the probability of observing results at least as extreme as your data, assuming the null hypothesis is true.
- p = 0.03 means: if there were truly no effect, there's a 3% chance of seeing data this extreme by random chance
- p < 0.05 does NOT mean "95% probability the effect is real"
- p < 0.05 does NOT mean the effect is large or practically significant
Common misuses:
- Treating p-value as proof of truth (it's just evidence)
- Running until significant (p-hacking)
- Ignoring effect size alongside p-value
- Not correcting for multiple comparisons
4. What is the difference between Type I and Type II errors?
| Error | Also called | Definition | Real example |
|---|---|---|---|
| Type I (α) | False positive | Reject true null | Declaring a feature improves conversion when it doesn't |
| Type II (β) | False negative | Fail to reject false null | Missing a real conversion lift |
Power = 1 - β = probability of detecting a real effect. Increasing sample size reduces both errors.
5. Explain the difference between frequentist and Bayesian statistics.
| Aspect | Frequentist | Bayesian |
|---|---|---|
| Probability | Long-run frequency | Degree of belief |
| Parameters | Fixed, unknown | Random variables with distributions |
| Result | p-values, confidence intervals | Posterior distributions, credible intervals |
| Prior knowledge | Not incorporated | Explicitly encoded as prior |
| Interpretation | "If we repeated this 100×, 95% of CIs contain the true value" | "There's 95% probability the parameter is in this range" |
Bayesian example: Spam filter. Prior = base rate of spam (60%). Likelihood = P(contains "free gift" | spam). Posterior = updated spam probability given the email's content.
6. What probability distributions should every data scientist know?
| Distribution | Use case | Parameters |
|---|---|---|
| Normal | Heights, errors, CLT | μ, σ |
| Log-normal | Salaries, latency, prices | μ, σ of log(X) |
| Binomial | n Bernoulli trials (clicks, conversions) | n, p |
| Poisson | Count of events in fixed time | λ (rate) |
| Exponential | Time between Poisson events | λ |
| Beta | Prior for probabilities | α, β |
| Power law / Pareto | Social network degree, wealth | α |
Interview tip: Know when data is "approximately normal" vs. when to check for skewness (use log-normal) or count data (Poisson).
7. What is correlation vs. causation? Give an example.
Correlation means two variables move together. Causation means one causes the other.
Classic example: Ice cream sales correlate with drowning deaths — both increase in summer. Removing ice cream wouldn't reduce drowning. The confounder is season (more swimming + more ice cream).
How to move from correlation to causation:
- Randomised controlled experiments (A/B tests)
- Instrumental variables
- Difference-in-differences
- Regression discontinuity
- Propensity score matching (observational data)
8. What is the law of large numbers?
As sample size increases, the sample mean converges to the population mean. This is why A/B tests need large samples, and why casino advantages are reliable at scale but not in small play sessions.
Contrast with CLT: LLN says the average stabilises; CLT describes the distribution of that average.
Python & pandas
9. How do you handle missing values in pandas?
import pandas as pd
import numpy as np
df = pd.DataFrame({
'age': [25, np.nan, 30, np.nan, 22],
'salary': [50000, 60000, np.nan, 80000, 55000],
'city': ['NYC', 'LA', None, 'NYC', 'Chicago']
})
# Detect
df.isnull().sum()
df.isnull().mean() # proportion missing per column
# Drop
df.dropna() # rows with any NaN
df.dropna(subset=['age']) # only if age missing
df.dropna(thresh=3) # keep rows with at least 3 non-NaN
# Fill — numeric
df['age'].fillna(df['age'].mean()) # mean imputation
df['age'].fillna(df['age'].median()) # median (better for skewed)
df['salary'].fillna(method='ffill') # forward fill (time series)
# Fill — categorical
df['city'].fillna(df['city'].mode()[0]) # most frequent
df['city'].fillna('Unknown')
# Advanced: sklearn imputation
from sklearn.impute import SimpleImputer, KNNImputer
imp = KNNImputer(n_neighbors=5)
df[['age', 'salary']] = imp.fit_transform(df[['age', 'salary']])
| Method | Best for |
|---|---|
| Mean fill | Numeric, few missing, symmetric |
| Median fill | Numeric, skewed or outliers |
| Mode fill | Categorical |
| KNN imputation | Multiple correlated features |
| Model-based | MCAR/MAR data, complex patterns |
| Drop | Many missing, or MNAR |
10. How do you detect and handle outliers?
import numpy as np
import pandas as pd
data = pd.Series([10, 12, 11, 13, 100, 14, 9, 12])
# IQR method (robust)
Q1 = data.quantile(0.25)
Q3 = data.quantile(0.75)
IQR = Q3 - Q1
lower = Q1 - 1.5 * IQR
upper = Q3 + 1.5 * IQR
outliers = data[(data < lower) | (data > upper)]
# Z-score method (assumes normal distribution)
from scipy import stats
z_scores = np.abs(stats.zscore(data))
outliers_z = data[z_scores > 3]
# Modified Z-score (more robust)
median = np.median(data)
mad = np.median(np.abs(data - median))
modified_z = 0.6745 * (data - median) / mad
What to do with outliers:
- Investigate first — is it a data error or real?
- Cap/winsorize at 1st/99th percentile
- Use robust models (tree-based, quantile regression)
- Log transform to compress the scale
- Remove only if clearly erroneous
11. Explain groupby + agg in pandas.
df = pd.DataFrame({
'region': ['US', 'EU', 'US', 'EU', 'US'],
'product': ['A', 'A', 'B', 'B', 'A'],
'revenue': [100, 200, 150, 300, 120],
'units': [10, 20, 15, 30, 12]
})
# Single aggregation
df.groupby('region')['revenue'].sum()
# Multiple aggregations
df.groupby('region').agg(
total_revenue=('revenue', 'sum'),
avg_revenue=('revenue', 'mean'),
total_units=('units', 'sum'),
num_products=('product', 'nunique')
)
# Multiple groupby keys
df.groupby(['region', 'product'])['revenue'].sum().unstack()
# Custom aggregation
df.groupby('region')['revenue'].agg(
lambda x: x.quantile(0.75) - x.quantile(0.25) # IQR
)
# Transform (keeps original index, returns same-length Series)
df['revenue_rank'] = df.groupby('region')['revenue'].rank(ascending=False)
df['pct_of_region'] = df['revenue'] / df.groupby('region')['revenue'].transform('sum')
12. How do you merge/join DataFrames in pandas?
customers = pd.DataFrame({'id': [1,2,3], 'name': ['Alice','Bob','Charlie']})
orders = pd.DataFrame({'order_id': [101,102,103], 'customer_id': [1,1,2], 'amount': [50,30,80]})
# INNER JOIN
pd.merge(customers, orders, left_on='id', right_on='customer_id', how='inner')
# LEFT JOIN — keep all customers, NaN if no orders
pd.merge(customers, orders, left_on='id', right_on='customer_id', how='left')
# Multiple keys
pd.merge(df1, df2, on=['key1', 'key2'], how='inner')
# Concat (stack vertically)
pd.concat([df1, df2], ignore_index=True)
pd.concat([df1, df2], axis=1) # side by side
| Join type | Returns |
|---|---|
| inner | Only matching rows |
| left | All left rows + matching right |
| right | All right rows + matching left |
| outer | All rows from both |
EDA & Visualisation
13. What is your approach to exploratory data analysis (EDA)?
A systematic EDA workflow:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# 1. Shape & types
df.shape
df.dtypes
df.head()
# 2. Missing values
df.isnull().sum()
df.isnull().mean().sort_values(ascending=False)
# 3. Descriptive stats
df.describe() # numeric
df.describe(include='object') # categorical
# 4. Target variable distribution
sns.histplot(df['target'])
df['target'].value_counts(normalize=True) # class balance
# 5. Numeric distributions
df.hist(figsize=(12, 8), bins=30)
# 6. Correlations
sns.heatmap(df.corr(numeric_only=True), annot=True, fmt='.2f', cmap='coolwarm')
# 7. Categorical distributions
for col in df.select_dtypes('object').columns:
print(df[col].value_counts())
# 8. Bivariate — numeric vs target
sns.boxplot(x='category', y='target', data=df)
sns.scatterplot(x='feature1', y='target', data=df)
# 9. Check for duplicates
df.duplicated().sum()
14. How do you choose the right chart type?
| Goal | Chart |
|---|---|
| Distribution of one variable | Histogram, KDE, box plot |
| Compare groups | Bar chart, box plot, violin plot |
| Relationship between two numeric | Scatter plot, hex bin |
| Trend over time | Line chart |
| Part of whole | Pie chart (only ≤5 categories), stacked bar |
| Correlation matrix | Heatmap |
| Distribution of many variables | Pair plot (seaborn pairplot) |
| Ranking | Horizontal bar chart |
| Geographic | Choropleth, bubble map |
Rule: Use scatter for relationships, bars for comparisons, lines for trends. Avoid pie charts beyond 4-5 segments.
Feature Engineering
15. What is the difference between normalisation and standardisation?
| Technique | Formula | Result | Use when |
|---|---|---|---|
| Min-max normalisation | (x - min) / (max - min) | [0, 1] | Neural networks, image data |
| Standardisation (z-score) | (x - μ) / σ | μ=0, σ=1 | Linear models, SVM, PCA |
| Robust scaling | (x - median) / IQR | Centred, scale-robust | Outliers present |
| Log transform | log(x + 1) | Compresses right tail | Skewed distributions |
| Power transform (Box-Cox) | Varies | Normal-like | Generalises log transform |
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X_train) # fit on train only!
X_test_scaled = scaler.transform(X_test) # transform test
Critical: Always fit scalers on training data only. Fitting on test data causes data leakage.
16. How do you encode categorical variables?
| Method | When to use | Pros | Cons |
|---|---|---|---|
| Label encoding | Ordinal categories | Simple | Implies false order for nominal |
| One-hot encoding | Nominal, few categories (<15) | No order assumption | High-dimensional |
| Target encoding | Nominal, many categories | Compact, captures signal | Leakage risk, needs smoothing |
| Frequency encoding | High cardinality | Simple, no leakage | Loses cardinality info |
| Binary encoding | Moderate cardinality | Compact | Less interpretable |
| Embedding (DL) | Very high cardinality | Learns representation | Needs large data |
import pandas as pd
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
# One-hot
pd.get_dummies(df['city'], drop_first=True)
# Target encoding (manual with smoothing)
def target_encode(series, target, smoothing=10):
global_mean = target.mean()
stats = pd.DataFrame({'target': target, 'cat': series})
agg = stats.groupby('cat')['target'].agg(['mean', 'count'])
smooth = (agg['count'] * agg['mean'] + smoothing * global_mean) / (agg['count'] + smoothing)
return series.map(smooth)
17. What is feature selection and what methods exist?
| Category | Methods |
|---|---|
| Filter | Correlation coefficient, chi-squared, ANOVA F-test, mutual information |
| Wrapper | Recursive Feature Elimination (RFE), forward/backward selection |
| Embedded | L1 regularisation (Lasso), tree feature importances |
| Dimensionality reduction | PCA, t-SNE, UMAP (for visualisation) |
from sklearn.feature_selection import SelectKBest, f_classif, RFE
from sklearn.ensemble import RandomForestClassifier
# Filter: top k features by ANOVA F-test
selector = SelectKBest(f_classif, k=10)
X_selected = selector.fit_transform(X_train, y_train)
# Embedded: Lasso
from sklearn.linear_model import Lasso
lasso = Lasso(alpha=0.01).fit(X_train, y_train)
selected = [f for f, coef in zip(features, lasso.coef_) if coef != 0]
# Tree importance
rf = RandomForestClassifier().fit(X_train, y_train)
importances = pd.Series(rf.feature_importances_, index=features).sort_values(ascending=False)
Model Evaluation
18. When do you use accuracy vs. precision vs. recall vs. F1?
| Metric | Formula | Use when |
|---|---|---|
| Accuracy | (TP+TN) / (TP+TN+FP+FN) | Balanced classes, equal cost of errors |
| Precision | TP / (TP+FP) | False positives are costly (spam filter, fraud alert) |
| Recall | TP / (TP+FN) | False negatives are costly (cancer screening, fraud detection) |
| F1 | 2 × Precision×Recall / (P+R) | Imbalanced classes, balance P and R |
| F-beta | (1+β²) × P×R / (β²P+R) | Custom P/R tradeoff |
| ROC AUC | Area under ROC curve | Rank-ordering, threshold-independent |
| PR AUC | Area under PR curve | Highly imbalanced datasets |
Rules of thumb:
- Cancer diagnosis: maximize recall (missing cancer is catastrophic)
- Spam filter: maximize precision (false positives annoy users)
- Credit scoring: AUC (need ranking, not one threshold)
- Class imbalance 1:100+: use PR AUC, not ROC AUC
19. What is cross-validation and why do you need it?
from sklearn.model_selection import cross_val_score, StratifiedKFold
from sklearn.ensemble import GradientBoostingClassifier
model = GradientBoostingClassifier()
# 5-fold CV
scores = cross_val_score(model, X, y, cv=5, scoring='roc_auc')
print(f"AUC: {scores.mean():.3f} ± {scores.std():.3f}")
# Stratified (preserves class proportion) — use for classification
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(model, X, y, cv=cv, scoring='f1')
# Time series: use TimeSeriesSplit (no future leakage)
from sklearn.model_selection import TimeSeriesSplit
tscv = TimeSeriesSplit(n_splits=5)
Why CV matters:
- Single train/test split has high variance — different random splits give different results
- CV averages over multiple splits for stable estimates
- Enables hyperparameter tuning without touching the test set
- Detects overfitting
20. How do you handle class imbalance?
| Technique | How | When |
|---|---|---|
| Oversample minority | SMOTE, RandomOverSampler | Small dataset |
| Undersample majority | RandomUnderSampler, Tomek links | Large dataset |
| Class weights | class_weight='balanced' in sklearn |
Quick and effective |
| Change threshold | Lower decision threshold | Maximize recall |
| Ensemble | BalancedBaggingClassifier | Robust |
| Different metric | Use F1, PR AUC, not accuracy | Evaluation |
| Collect more data | Best long-term solution | — |
from sklearn.utils.class_weight import compute_class_weight
from imblearn.over_sampling import SMOTE
# Class weights (fastest)
weights = compute_class_weight('balanced', classes=[0,1], y=y_train)
model = RandomForestClassifier(class_weight={0: weights[0], 1: weights[1]})
# SMOTE
sm = SMOTE(random_state=42)
X_resampled, y_resampled = sm.fit_resample(X_train, y_train)
# ⚠️ Only apply SMOTE to training data!
ML Fundamentals
21. Explain the bias-variance tradeoff.
Bias = error from wrong assumptions (underfitting). A linear model on non-linear data has high bias.
Variance = sensitivity to training data fluctuations (overfitting). A deep decision tree memorises noise.
Total error = Bias² + Variance + Irreducible noise
| Model | Bias | Variance |
|---|---|---|
| Linear regression | High | Low |
| Decision tree (deep) | Low | High |
| Random forest | Low-medium | Medium |
| Gradient boosting | Low | Medium-Low |
| Neural network (small) | High | Low |
| Neural network (large) | Low | High |
Remedies for high variance: regularisation, more data, simpler model, cross-validation. Remedies for high bias: more features, more complex model, better feature engineering.
22. How does gradient boosting work?
Gradient boosting builds an ensemble of weak learners (typically shallow decision trees) sequentially, where each tree corrects errors of the previous.
F₀(x) = initial prediction (mean)
For m = 1 to M:
rₘ = negative gradient of loss w.r.t. current prediction ← residuals
hₘ = tree fitted to residuals
Fₘ(x) = Fₘ₋₁(x) + η × hₘ(x) ← η = learning rate
Key hyperparameters:
n_estimators— number of trees (more → lower bias, higher variance)learning_rate— shrinkage per tree (lower → need more trees, more regularised)max_depth— tree complexity (3-5 typical)subsample— stochastic gradient boosting (0.8 common)min_samples_leaf— regularisation
XGBoost, LightGBM, CatBoost all implement gradient boosting with hardware optimisations.
23. What is regularisation and when do you use L1 vs. L2?
Both L1 and L2 add a penalty to the loss function to discourage large weights.
| Regularisation | Penalty | Effect | Use when |
|---|---|---|---|
| L2 (Ridge) | λ × Σwᵢ² | Shrinks weights evenly, never zero | All features probably useful |
| L1 (Lasso) | λ × Σ | wᵢ | |
| Elastic Net | α L1 + (1-α) L2 | Combines both | Correlated features + sparsity |
from sklearn.linear_model import Ridge, Lasso, ElasticNet
ridge = Ridge(alpha=1.0) # L2
lasso = Lasso(alpha=0.01) # L1
enet = ElasticNet(alpha=0.01, l1_ratio=0.5)
A/B Testing
24. Walk me through designing an A/B test.
Step-by-step:
- Define hypothesis — "Changing CTA button from green to orange will increase click-through rate."
- Choose metric — primary KPI (CTR), guardrail metrics (session length, bounce rate)
- Calculate sample size:
from statsmodels.stats.power import TTestIndPower # 80% power, 5% significance, detect 2% relative lift on 10% baseline CTR baseline = 0.10 mde = 0.002 # minimum detectable effect (absolute) effect_size = mde / (baseline * (1 - baseline)) ** 0.5 analysis = TTestIndPower() n = analysis.solve_power(effect_size=effect_size, alpha=0.05, power=0.80) - Randomise — hash user ID modulo 100, assign 0-49 → control, 50-99 → treatment
- Run test — wait for predetermined sample size (don't peek and stop early)
- Analyse — two-proportion z-test for CTR, t-test for continuous metrics
- Ship or reject — check p-value + practical significance + guardrail metrics
25. What are common A/B testing pitfalls?
| Pitfall | Why it's a problem | Fix |
|---|---|---|
| Stopping early | Type I error inflation (p-hacking) | Fix sample size before running |
| Multiple testing | Each test inflates false positive rate | Bonferroni correction or sequential testing |
| Network effects | Users influence each other | Cluster randomisation |
| Novelty effect | Users behave differently because it's new | Run for 2+ business cycles |
| Sample ratio mismatch | Assignment ratio differs from intended | Check SRM first |
| Wrong unit of randomisation | User vs. session vs. page view | Use user-level when possible |
| Peeking | Continuous monitoring without correction | Pre-register stopping rule |
26. How do you decide if an A/B test result is practically significant?
Statistical significance (p < 0.05) alone is not enough — with large samples even tiny effects are significant.
- Effect size: Did CTR go from 10.0% to 10.1%? Is that worth deploying?
- Confidence interval: "The lift is between 0.5% and 2.1%" — entire CI above minimum acceptable?
- Business impact: Effect size × daily users × revenue per conversion = $X/month
- Cost of shipping: Engineering effort, complexity, maintenance
- Guardrail metrics: Did any secondary metric move negatively?
SQL for Data Science
27. How do you calculate a 7-day rolling average in SQL?
-- Daily active users with 7-day rolling average
SELECT
date,
dau,
AVG(dau) OVER (
ORDER BY date
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
) AS rolling_7d_avg
FROM daily_stats
ORDER BY date;
28. How do you find user retention in SQL?
-- Day-1 retention: users who returned the day after registration
WITH cohort AS (
SELECT
user_id,
DATE(MIN(event_time)) AS signup_date
FROM events
WHERE event_type = 'signup'
GROUP BY user_id
),
activity AS (
SELECT DISTINCT
user_id,
DATE(event_time) AS active_date
FROM events
)
SELECT
c.signup_date,
COUNT(DISTINCT c.user_id) AS cohort_size,
COUNT(DISTINCT a.user_id) AS retained,
COUNT(DISTINCT a.user_id) * 1.0 / COUNT(DISTINCT c.user_id) AS d1_retention
FROM cohort c
LEFT JOIN activity a
ON c.user_id = a.user_id
AND a.active_date = c.signup_date + INTERVAL '1 day'
GROUP BY c.signup_date
ORDER BY c.signup_date;
29. Write a query to find the second-highest salary per department.
-- Using DENSE_RANK
WITH ranked AS (
SELECT
employee_id,
department,
salary,
DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS rk
FROM employees
)
SELECT department, salary AS second_highest_salary
FROM ranked
WHERE rk = 2;
Business Acumen
30. Daily active users dropped 20% yesterday. How do you investigate?
A systematic diagnosis framework:
1. Is the drop real?
- Check data pipeline: ETL delay? Missing events? Logging bug?
- Check other metrics: if all metrics dropped proportionally → likely data issue
2. Scope the problem
- By platform: iOS / Android / Web
- By geography: specific country or global?
- By user segment: new vs. returning users?
- By traffic source: organic / paid / email?
3. What changed?
- Any deployments or feature flags yesterday?
- Marketing campaign started or ended?
- Competitor launched something?
- External event (holiday, news event)?
- Push notification failure?
4. Form hypotheses ranked by likelihood
- Most likely: data pipeline issue
- Next: feature deployment caused friction
- Then: external factor (holiday in key market)
5. Validate each hypothesis with data
6. Communicate findings + recommended action
31. How would you measure the success of a new feature?
Framework: Define metrics before launching.
Goal metric (primary): Directly measures feature value
- New search feature → queries per session, search success rate
Engagement metric: Feature adoption
- % of active users who used the feature
Quality metric: Is the experience good?
- Feature-specific satisfaction, error rate, P95 latency
Guardrail metrics: Ensure you haven't broken anything
- Core engagement (DAU, session length), revenue, retention
Evaluation:
- Short-term: A/B test for 2+ weeks
- Long-term: cohort analysis (do users who adopted retain better?)
Practical ML Scenarios
32. How do you prevent data leakage?
Data leakage occurs when training data contains information that wouldn't be available at prediction time — causing falsely optimistic CV scores that fail in production.
Common sources:
- Target in features: Including columns derived from the label
- Future data in past prediction: Using next day's features to predict today
- Global statistics before splitting: Fitting a scaler on the full dataset
- Duplicate records across splits: Same user in train and test
# ❌ WRONG: leakage
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X) # all data!
X_train, X_test = train_test_split(X_scaled)
# ✅ CORRECT: no leakage
X_train, X_test, y_train, y_test = train_test_split(X, y)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train) # fit on train only
X_test = scaler.transform(X_test) # transform test
33. How do you approach a churn prediction problem?
1. Define churn: no activity for 30 days? Cancelled subscription? Context-dependent.
2. Frame as classification: binary (churned/active) or survival analysis
3. Build features:
- Recency (days since last action)
- Frequency (actions per week)
- Monetary (spend per month)
- Engagement trajectory (declining?)
- Support tickets, plan type, usage of key features
4. Handle class imbalance (often 5-20% churn)
- Use class_weight='balanced'
- Evaluate with F1, PR AUC
5. Model choice:
- Logistic regression (interpretable baseline)
- Gradient boosting (usually best performance)
- Survival analysis if time-to-churn matters
6. Calibrate probabilities (CalibratedClassifierCV)
7. Business action: at what threshold do we intervene?
Optimise threshold for precision/recall tradeoff given intervention cost
8. Monitor: retrain monthly, watch for drift in feature distributions
34. How would you build a recommendation system?
| Approach | How | When |
|---|---|---|
| Popularity-based | Recommend most popular items | Cold start, new users |
| Content-based | Match item features to user profile | Good item metadata |
| Collaborative filtering (user-user) | Users similar to you liked X | Dense interaction matrix |
| Collaborative filtering (item-item) | Users who liked A also liked B | Stable item catalogue |
| Matrix factorisation (ALS, SVD) | Learn latent factors | Standard CF |
| Two-tower neural network | Learn user+item embeddings | Large scale |
| Hybrid | Combine content + CF | Best of both |
Cold start problem:
- New user → use demographics + onboarding preferences
- New item → use content features
Evaluation: Offline (precision@K, recall@K, NDCG) + Online A/B test (CTR, conversion).
Communication & Scenarios
35. How do you explain a complex model to a non-technical stakeholder?
Use the 3-level explanation:
What does it do? — "Given a customer's history, the model predicts how likely they are to leave us in the next 30 days."
How accurate is it? — "Of the customers it flags as high-risk, 65% actually churn. We catch 80% of all churners."
What should we do with it? — "If we sort customers by this score and call the top 500 highest-risk ones, our retention team can prevent ~$200k in monthly revenue loss."
Avoid: accuracy percentages without context, technical jargon, black-box framing.
36. What is the difference between a data scientist, data analyst, and ML engineer?
| Role | Focus | Primary tools | Output |
|---|---|---|---|
| Data Analyst | Historical insights, reporting | SQL, Excel, Tableau, Python | Dashboards, ad hoc reports |
| Data Scientist | Statistical modelling, A/B tests, predictive models | Python, R, sklearn, notebooks | Experiments, models, insights |
| ML Engineer | Production ML systems | Python, TensorFlow/PyTorch, MLflow, Spark | Deployed models, pipelines |
| Analytics Engineer | Data transformation, reliable data models | dbt, SQL, Spark | Clean data for analysts/DS |
In practice, roles overlap heavily at startups. Large companies have more specialisation.
Remaining Interview Topics
37. What is PCA and when do you use it?
Principal Component Analysis finds orthogonal axes (principal components) that capture maximum variance. Used for:
- Dimensionality reduction before modelling (speed, remove correlated features)
- Visualisation (2D/3D projection of high-dim data)
- Noise reduction
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
pca = PCA(n_components=2)
X_2d = pca.fit_transform(X_scaled)
print(pca.explained_variance_ratio_) # variance per component
print(pca.explained_variance_ratio_.cumsum()) # cumulative
plt.scatter(X_2d[:, 0], X_2d[:, 1], c=y)
Limitations: Only captures linear relationships. For non-linear: t-SNE or UMAP (visualisation only). PCA requires scaling first.
38. What is the difference between K-means and hierarchical clustering?
| Aspect | K-means | Hierarchical |
|---|---|---|
| Output | k flat clusters | Dendrogram (all clusterings) |
| k selection | Must specify upfront | Choose cut level after |
| Scalability | O(n) — scales well | O(n²) or O(n² log n) |
| Shape assumption | Spherical, similar size | Flexible |
| Result stability | Non-deterministic | Deterministic |
| Interpreting | Simple centroids | Can inspect tree |
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
# Elbow method for k selection
inertias = []
for k in range(2, 11):
km = KMeans(n_clusters=k, random_state=42).fit(X_scaled)
inertias.append(km.inertia_)
# Silhouette score (higher = better, range -1 to 1)
km = KMeans(n_clusters=3, random_state=42).fit(X_scaled)
print(silhouette_score(X_scaled, km.labels_))
39. Explain precision-recall tradeoff with a concrete example.
Cancer screening model:
- At threshold 0.3: Recall=0.95, Precision=0.20 → catch 95% of cancers, but 80% of positives are false alarms → acceptable (missing cancer is catastrophic)
- At threshold 0.7: Recall=0.60, Precision=0.75 → miss 40% of cancers but fewer false alarms → not acceptable
Spam filter:
- At threshold 0.3: Recall=0.98, Precision=0.60 → catch nearly all spam but 40% of flagged are real emails → bad
- At threshold 0.8: Recall=0.70, Precision=0.97 → miss some spam but rarely flag real emails → acceptable
The optimal threshold depends on the cost ratio of false positives to false negatives.
40. How do you monitor a deployed model?
| Monitor | What to track | Alert when |
|---|---|---|
| Data drift | Input feature distributions (PSI, KS test) | PSI > 0.2 |
| Concept drift | Model performance vs. ground truth | AUC drops > 5% |
| Prediction drift | Output score distribution | Sudden shift |
| Infrastructure | Latency, throughput, error rate | P95 latency > SLA |
| Business metric | Downstream KPI (CTR, conversion) | Week-over-week drop |
from scipy.stats import ks_2samp
# Kolmogorov-Smirnov test for distribution drift
train_feature = X_train['age']
live_feature = new_data['age']
stat, p_value = ks_2samp(train_feature, live_feature)
if p_value < 0.05:
print("Drift detected in 'age'")
41. What is the difference between bagging and boosting?
| Aspect | Bagging | Boosting |
|---|---|---|
| Sampling | Bootstrap (with replacement) | Weighted |
| Training | Parallel, independent | Sequential |
| Goal | Reduce variance | Reduce bias |
| Weights | Equal | Higher for misclassified |
| Error correcting | No — averages independent models | Yes — each corrects previous |
| Overfitting risk | Low | Moderate (needs early stopping) |
| Examples | Random Forest | Gradient Boosting, XGBoost, AdaBoost |
42. What is the difference between a confusion matrix and ROC curve?
Confusion matrix: shows TP/FP/TN/FN at one threshold — gives precision, recall, accuracy at that point.
ROC curve: plots TPR vs. FPR across all thresholds — threshold-independent performance measure. AUC = probability that model ranks a random positive higher than a random negative.
When to prefer each:
- Confusion matrix: when you've decided on a threshold and want to understand specific errors
- ROC/AUC: when comparing models across all thresholds, or doing model selection
- PR curve: when class imbalance is severe (positive class rare)
43. What is transfer learning and when do you use it?
Transfer learning uses a model pre-trained on a large dataset as a starting point, then fine-tunes on your (smaller) target dataset.
from transformers import AutoTokenizer, AutoModelForSequenceClassification
# Pre-trained BERT fine-tuned for sentiment
model = AutoModelForSequenceClassification.from_pretrained(
"bert-base-uncased", num_labels=2
)
# Fine-tune on your domain data
When to use:
- Limited labelled data in your domain
- Target task similar to pre-training task
- Pre-training data domain overlaps with yours (NLP: general text → medical text)
Common in:
- NLP (BERT, GPT fine-tuning)
- Computer vision (ResNet/EfficientNet backbone for custom classification)
44. What are embeddings and how are they used?
An embedding is a dense low-dimensional vector representation of a high-dimensional entity (word, user, product).
from sentence_transformers import SentenceTransformer
import numpy as np
model = SentenceTransformer('all-MiniLM-L6-v2')
sentences = ["Paris is beautiful", "I love France", "Python is great"]
embeddings = model.encode(sentences) # (3, 384) arrays
# Cosine similarity
from sklearn.metrics.pairwise import cosine_similarity
sim = cosine_similarity(embeddings)
Uses:
- Semantic search: find similar documents
- Recommendation: user/item embeddings for collaborative filtering
- Anomaly detection: flag items far from cluster centres
- Feature input for downstream models
45. How do you approach a time series forecasting problem?
# 1. Plot and understand
import matplotlib.pyplot as plt
ts.plot()
# Identify: trend? seasonality? irregular spikes?
# 2. Decompose
from statsmodels.tsa.seasonal import seasonal_decompose
decomp = seasonal_decompose(ts, model='additive', period=7)
decomp.plot()
# 3. Check stationarity
from statsmodels.tsa.stattools import adfuller
stat, p, *_ = adfuller(ts)
# If p > 0.05: non-stationary → difference the series
# 4. Model options:
# - Statistical: ARIMA, SARIMA, Exponential Smoothing (Prophet)
# - ML: Features (lag, rolling stats, calendar) → GBM
# - DL: LSTM, Temporal Fusion Transformer, N-BEATS
from prophet import Prophet
model = Prophet(yearly_seasonality=True, weekly_seasonality=True)
model.fit(df) # df has 'ds' (date) and 'y' (value) columns
future = model.make_future_dataframe(periods=30)
forecast = model.predict(future)
Anti-patterns table
| Anti-pattern | Problem | Fix |
|---|---|---|
| Fitting scaler on all data | Data leakage | Fit only on training set |
| Using accuracy on imbalanced data | Misleadingly high scores | Use F1, PR AUC |
| Ignoring class imbalance | Model ignores minority class | Class weights or resampling |
| Evaluating on training data | Guarantees overfitting | Always use held-out test/CV |
| Using all features without selection | Multicollinearity, noise | Feature importance analysis |
| Not normalising for gradient-based models | Slow or failed convergence | StandardScaler |
| Manual loops on DataFrames | O(n) Python overhead | Vectorised pandas operations |
| Not checking for drift in production | Silent performance degradation | Monitor feature + prediction distributions |
Data science vs. related roles
| Dimension | Data Analyst | Data Scientist | ML Engineer | Data Engineer |
|---|---|---|---|---|
| Primary language | SQL, Python | Python, R | Python, C++ | Python, Scala |
| Core skill | Querying, visualisation | Statistics, modelling | System design | Pipelines, infra |
| Output | Reports, dashboards | Models, experiments | Production systems | Data pipelines |
| Coding level | Moderate | High | Very high | Very high |
| Stats knowledge | Basic | Deep | Moderate | Basic |
| Salary range (US) | $70-110k | $100-160k | $120-200k | $110-170k |
Common mistakes
| Mistake | Why it's wrong |
|---|---|
| Skipping EDA | Miss data issues before modelling |
| Tuning on test set | Overfits to test data, need separate validation |
| Ignoring business context | Technically correct, practically useless |
| Complex model without baseline | Can't measure improvement |
| No reproducibility (random seeds) | Results can't be verified |
| Forgetting to scale before PCA/SVM/kNN | Distance-based methods break |
| Treating all missing values the same | MCAR vs MAR vs MNAR need different treatment |
| Not communicating uncertainty | "The model is 85% accurate" without CI misleads |
FAQ
Q: What programming languages do data scientists use most in 2025?
Python dominates (80%+) with pandas, NumPy, sklearn, matplotlib, and LightGBM. SQL is the second must-have. R is still used in academia and pharma. Julia is growing for numerical computing. Most production ML is Python.
Q: Do I need a PhD to become a data scientist?
No. A BS/MS in statistics, CS, maths, or engineering is sufficient for most industry roles. A PhD helps for research-focused positions (Meta AI Research, DeepMind) or cutting-edge algorithm work. Industry values portfolio projects, Kaggle results, and practical ML skills over academic credentials.
Q: What is the difference between a data science notebook and production code?
Notebooks (Jupyter) are for exploration, EDA, and prototyping — linear execution, no tests, messy OK. Production code is modular, version-controlled, tested, logged, with error handling and scheduled retraining. Most ML projects start as notebooks and get refactored into production Python packages or ML pipelines (MLflow, Airflow, Kubeflow).
Q: Is deep learning replacing classical machine learning for data scientists?
For tabular data (most business problems): no. Tree-based methods (LightGBM, XGBoost, CatBoost) still outperform neural nets on structured data. Deep learning dominates for images, text, audio, and video. Data scientists working on business analytics use classical ML 90% of the time.
Q: What Kaggle competitions are most useful for data science interviews?
Tabular competitions (Porto Seguro, Titanic, Housing Prices) for feature engineering. NLP competitions (Jigsaw, feedback) for text. Time-series competitions (Store Sales, M5) for forecasting. Being in the top 10% on any moderately competitive competition is impressive — focus on learning over ranking.
Q: How do I transition from data analyst to data scientist?
Learn statistics (hypothesis testing, probability, regression) beyond basic reporting. Get comfortable with scikit-learn and building end-to-end ML pipelines. Complete a Kaggle competition. Build a project that predicts something (churn, price, demand) with proper train/test evaluation. Study A/B testing methodology deeply. The main gaps are usually statistics and coding depth, not domain knowledge.