This page is for anyone facing a machine learning round, from a first analyst or ML job to a senior applied role. Most rounds open with supervised versus unsupervised learning and the bias-variance trade-off, then test overfitting and regularisation, linear and logistic regression, trees, boosting, SVMs, k-means and PCA. Stronger rounds dig into metrics, cross-validation, class imbalance, data leakage and what happens after a model ships. Each question shows what the interviewer is really checking, the shape of a strong answer and a short answer you can say out loud. Practise saying them, then swap in your own projects.
Search all questions by round, difficulty and level, or save the ones you want to practise.
Supervised: you have labelled examples and learn a mapping from inputs to a known target; classification or regression.
Unsupervised: no labels; you look for structure such as clusters or a smaller set of dimensions.
Examples: spam filtering or price prediction versus customer segmentation or anomaly spotting.
"In supervised learning every training example comes with the answer, the label, and the model learns to predict that label for new inputs. If the label is a category, like spam or not spam, it's classification. If it's a number, like a house price, it's regression. In unsupervised learning there's no label at all. The model looks for structure on its own, like grouping customers with similar buying habits using k-means, or squeezing fifty correlated columns into a handful with PCA. The practical difference is data: supervised needs labels, which are often the expensive part, while unsupervised works on raw data but gives you groups or patterns you still have to interpret. There's also semi-supervised learning, where a few labels are combined with lots of unlabelled data."
Defining the two only as 'with a teacher' and 'without a teacher' with no concrete example or mention of labels.
Bias: error from a model too simple to capture the pattern; it underfits.
Variance: error from a model that changes a lot with the training sample; it overfits.
Diagnosis: high training error means bias; low training error but much higher validation error means variance.
Fixes: more capacity or features for bias; more data, regularisation or a simpler model for variance.
"Bias is error from wrong assumptions, like fitting a straight line to a curved relationship. The model misses the pattern even on training data. Variance is error from being too sensitive to the particular sample you trained on, like a very deep tree that memorises noise. For squared error, the expected test error splits into bias squared, variance and irreducible noise. Making a model more flexible usually lowers bias but raises variance, so the goal is the sweet spot between them. To diagnose, I compare training and validation error. If both are high and close together, it's bias, so I add features or use a more flexible model. If training error is low but validation error is much higher, it's variance, so I get more data, add regularisation, or simplify. Learning curves make this very clear."
Saying more data always helps, or mixing up which of bias and variance goes with overfitting.
Name it: a big gap between training and validation scores is overfitting.
Check first: make sure the split itself is sound and the validation set is representative.
Fixes: more data, fewer or better features, regularisation, a simpler model, early stopping, limits on tree depth.
"A big gap like that means the model is overfitting: it has learned noise and quirks of the training set that don't generalise. Before fixing the model, I check the split is fair, because a validation set from a different period or population can create a gap on its own. Then I try the cheap fixes. I reduce complexity, for example capping tree depth or raising the minimum samples per leaf. I add regularisation, like L2 on a linear model. For boosting or anything trained in rounds, I use early stopping on the validation score. I also look at the features: dropping noisy or redundant ones often helps. And if I can get more data, that's the most reliable fix of all. I judge each change with cross-validation, not a single split."
Jumping straight to a different, more complex algorithm without first checking the split or reducing complexity.
L1 (Lasso): adds the sum of absolute weights; drives some weights to zero, so it also selects features.
L2 (Ridge): adds the sum of squared weights; shrinks all weights smoothly, rarely to zero.
Why zeros: the L1 penalty has a constant pull toward zero, however small the weight is; the L2 pull fades as the weight shrinks.
Choice: L1 for sparse, interpretable models; L2 for correlated features; Elastic Net mixes both.
"Both add a penalty on the size of the weights to the loss, and a strength parameter controls how hard we push. L1 adds the sum of the absolute values, L2 adds the sum of the squares. The difference shows in the gradient. With L2, the push toward zero is proportional to the weight, so as a weight gets small the push gets small too, and it settles near zero but not at it. With L1, the push is the same size no matter how small the weight is, so weak features get driven all the way to zero. Geometrically, the L1 constraint region has corners on the axes, and the best point often lands on one. So I use L1 when I want feature selection, and L2 when features are correlated, because L1 tends to keep one of a correlated group almost at random."
Saying L2 removes features, or not knowing that the penalty strength has to be tuned.
Linearity: the target is a linear function of the features, after any transforms you add.
Errors: independent, with constant spread (homoscedasticity), and roughly normal for classic inference.
Features: no severe multicollinearity, or coefficients become unstable.
In practice: check residual plots; normality matters for p-values and intervals, much less for prediction.
"Linear regression assumes the relationship is linear in the features, that the errors are independent of each other, that they have roughly constant variance across the range, and, for the classic tests and intervals, that they're roughly normal. It also struggles when features are highly correlated, because the coefficients get unstable even if predictions stay fine. In practice I care most about linearity and independence. If the relationship is curved, the model is just wrong, so I'd add transforms or interaction terms. If errors are correlated, like in time series, my error estimates are too optimistic. Normality mostly matters when I'm reporting p-values or intervals, not when I only need predictions. My main tool is a residual plot: a pattern or a funnel shape tells me which assumption is breaking."
Claiming the features themselves must be normally distributed; the assumption is about the errors.
Output: a sigmoid of a linear score, so predictions are probabilities between 0 and 1.
Linear regression fails: outputs go below 0 and above 1, and outliers drag the boundary.
Log loss: heavily punishes confident wrong answers and, with the sigmoid, gives a convex problem.
Reading it: each coefficient changes the log-odds of the positive class.
"Logistic regression takes a linear combination of the features and passes it through a sigmoid, so the output is a probability between zero and one. Linear regression on a zero-one label can predict values below zero or above one, and a few extreme points can shift the line and move the decision boundary badly. For training, we use log loss, which is the negative log-likelihood of the labels. It punishes a confident wrong prediction very hard, which is what you want. And with the sigmoid, log loss gives a convex problem, so there are no bad local minima for gradient descent to get stuck in. Squared error combined with a sigmoid isn't convex, and its gradient almost vanishes when the model is confidently wrong. A nice side effect is interpretability: each coefficient is the change in log-odds for a one-unit change in that feature."
Calling logistic regression a regression model that predicts a class directly, with no mention of probabilities or the sigmoid.
Margin: find the boundary with the widest gap to the nearest points; those points are the support vectors.
Soft margin: C sets the cost of points inside the margin or on the wrong side; high C fits tighter, low C allows more slack.
Kernel trick: compute similarity as if in a higher-dimensional space without building it, giving curved boundaries.
"An SVM looks for the boundary that separates the classes with the widest possible margin. Only the points closest to the boundary, the support vectors, decide where it goes, which is why it's called that. Real data overlaps, so we use a soft margin, and C controls how much we pay for points that break the margin. A high C tries hard to classify every training point, giving a narrower margin and more risk of overfitting. A low C accepts some mistakes for a wider, smoother boundary. The kernel trick lets the SVM draw curved boundaries. Instead of mapping the data into a higher-dimensional space, it uses a kernel function, like RBF, that gives the inner products in that space directly. SVMs need scaled features and get slow on very large datasets."
Describing the kernel trick as actually transforming every point into a huge feature space, or having C's direction backwards.
Greedy search: at each node, try features and thresholds and pick the split that most reduces impurity.
Impurity: Gini or entropy for classification; variance or squared error for regression.
Stopping: max depth, minimum samples per leaf or split, or pruning after growing.
"A decision tree looks at every feature and a range of possible thresholds, and picks the split that makes the child nodes as pure as possible. For classification that's usually measured with Gini impurity or entropy, where entropy gives you information gain. For regression it's the reduction in variance, or squared error. It does this greedily, one node at a time, without looking ahead. Left alone, it keeps splitting until every leaf is pure, which means it memorises the training data. So I control it with a maximum depth, a minimum number of samples per leaf, or a minimum gain before splitting, or I grow it fully and prune it back using validation performance. A nice property is that trees don't need feature scaling, because a split only cares about order."
Not knowing any impurity measure, or thinking the tree finds the globally best tree rather than splitting greedily.
Random forest: many deep trees on bootstrap samples with random feature subsets; average them; mainly cuts variance.
Gradient boosting: shallow trees added one after another, each fitting the errors of the ensemble so far; mainly cuts bias.
Trade-off: forests are robust with little tuning and train in parallel; boosting is usually more accurate but needs tuning and early stopping.
"A random forest trains many deep trees independently. Each one sees a bootstrap sample of the rows and a random subset of features at each split, so the trees are different from each other, and averaging them cancels out a lot of the variance. Adding more trees doesn't make it overfit, it just stops improving. Gradient boosting builds trees one after another. Each new, usually shallow, tree is fitted to the negative gradient of the loss, which for squared error is just the residuals, and a learning rate scales its contribution. That steadily reduces bias, but with too many rounds it will overfit, so I use early stopping. In practice I reach for a random forest as a strong baseline that needs little tuning, and boosting when I have time to tune and want the best accuracy on tabular data."
Saying both just combine many trees, with no difference between parallel averaging and sequential error correction.
Loop: pick k starting centres, assign each point to the nearest, move each centre to its points' mean, repeat until stable.
Choosing k: elbow on within-cluster distance, silhouette score, and whether the clusters make business sense.
Limits: assumes round, similar-sized clusters; sensitive to scale, outliers and starting points.
"K-means starts with k centres, usually chosen with k-means plus plus so they're spread out. Then it alternates two steps: assign every point to its nearest centre, then move each centre to the mean of the points assigned to it. It repeats until assignments stop changing. That minimises the total squared distance of points to their centres, but only to a local minimum, so I run it several times with different starts. To choose k, I plot that total distance against k and look for the elbow, check silhouette scores, and ask whether the groups are useful to the business. It fails on long, curved or very unequal clusters, it's pulled by outliers, and because it uses distance, features must be scaled first or the biggest-unit column dominates."
Forgetting to scale features, or treating the elbow method as giving one correct k.
What: finds new orthogonal axes ordered by how much variance they capture; keep the top few.
How: centre the data (and usually scale it), then take the eigenvectors of the covariance matrix, in practice via SVD.
Use: many correlated features, visualisation, noise reduction, speeding up distance-based models.
Avoid: when you need interpretable features, or the signal lives in low-variance directions.
"PCA finds new axes for the data. The first is the direction along which the data varies most, the second is the most variable direction at right angles to the first, and so on. You keep the first few and drop the rest, choosing how many by the share of variance explained. Mechanically, you centre the data, usually standardise it so units don't dominate, and get the directions from the covariance matrix, in practice using SVD. I use it when I have many correlated features, to plot high-dimensional data in two dimensions, or to speed up something distance-based. I avoid it when people need to understand the features, because each component is a blend of everything. And since it ignores the label, it can throw away a low-variance direction that actually predicts the target."
Saying PCA picks the most important original features; it builds new combined ones.
Idea: split into k folds, train on k minus 1, validate on the one left out, rotate, average the scores.
Why: every row is used for validation once, so the estimate is less dependent on one lucky or unlucky split.
Variants: stratified for classification, grouped when rows share a user, forward-chaining for time series.
Still: keep a final test set untouched for the last check.
"With one split, the score depends heavily on which rows happened to land in the test set, especially with small data. In k-fold, I split the data into k parts, say five. I train on four, validate on the fifth, and repeat so each part is the validation set once. Then I look at the mean score and also the spread, because a big spread tells me the model is unstable. For classification I use stratified folds so each fold keeps the class balance. If several rows belong to the same customer, I use group folds so a customer never appears on both sides. For time series I don't shuffle; I train on the past and validate on the next period. And I still keep a separate test set for the final number."
Tuning on the cross-validation score and then reporting that same score as the final estimate of performance.
Precision: of the cases we flagged positive, how many really were.
Recall: of the real positives, how many we caught.
F1: the harmonic mean, useful when you need one number balancing both.
Pick by cost: screening misses are costly, so favour recall, with a follow-up test to catch false alarms.
"Precision answers: when the model says positive, how often is it right? It's true positives over everything we predicted positive. Recall answers: of all the actual positives, how many did we find? It's true positives over all real positives. F1 is the harmonic mean of the two, so it's only high when both are high. For disease screening, missing a sick person is usually much worse than a false alarm, because a false alarm leads to a follow-up test while a miss can mean no treatment. So I'd push recall high and accept lower precision, and set the threshold with the doctors based on how many extra follow-ups they can handle. For something like a spam filter it flips, because putting a real email in spam is the costly mistake."
Mixing up the denominators of precision and recall, or picking a metric without talking about the cost of errors.
ROC: true positive rate against false positive rate; AUC is the chance a random positive scores above a random negative.
The trap: with a huge number of negatives, even many false alarms are a tiny false positive rate, so ROC looks strong.
PR curve: precision against recall; it exposes the false alarms because precision counts them against the few positives.
Business view: precision and recall at the threshold or alert volume you'll really use.
"ROC plots true positive rate against false positive rate. The problem with one fraud in a thousand is the false positive rate's denominator: all the legitimate transactions. I could flag thousands of good transactions and the false positive rate would still look tiny, so the ROC curve hugs the top left and AUC looks great. The precision-recall curve doesn't hide that, because precision compares false alarms to true frauds directly. A random model's PR AUC sits at the positive rate, here about one in a thousand, not at 0.5, so the baseline is much lower and gains are easier to judge. In the end I'd report precision and recall at the threshold the fraud team will actually run, like how many true frauds we catch if analysts can review a fixed number of alerts a day."
Saying ROC AUC is always the right metric for classification, or not knowing what the axes of either curve are.
MAE: average absolute error in the target's units; every unit of error counts the same.
RMSE: squares errors before averaging, so large misses weigh much more; also in the target's units.
R-squared: share of variance explained compared with predicting the mean; unitless, can be negative on new data.
Choose: RMSE when big misses are disproportionately costly, MAE when they aren't; R-squared for context, not alone.
"MAE is the average absolute error, so if I'm predicting delivery time in minutes, an MAE of eight means we're off by eight minutes on average. It treats every minute the same and is less swayed by a few extreme cases. RMSE squares the errors first, so one miss of forty minutes hurts far more than four misses of ten. If big misses are what really cost us, RMSE is the better fit. Both are in the target's units, which makes them easy to explain. R-squared tells me how much of the variance I explain compared with just predicting the average. It's handy for context but has no units, and on a test set it can go negative if the model is worse than the mean. I usually report MAE or RMSE plus a naive baseline next to it."
Treating a high R-squared as proof the model is good without comparing errors to a baseline.
Metrics first: drop accuracy; use precision, recall, PR AUC and stratified splits.
Training: class weights in the loss, or resample the training set only (undersample, oversample, SMOTE).
Threshold: tune the decision threshold on validation data to the cost of each error.
Check: resampling or weighting distorts probabilities; recalibrate if scores are used as probabilities.
"First I fix the evaluation, because accuracy is useless here: predicting 'negative' for everything scores almost perfectly. I use stratified splits so every fold has positives, and I look at precision, recall and the precision-recall curve. For training, my first move is class weights, so a mistake on a positive costs more in the loss. Resampling is the other option, undersampling the majority or oversampling the minority, possibly with SMOTE, but only ever on the training data, never the validation or test sets. Often the biggest win is simply moving the decision threshold away from 0.5 to match the real cost of a miss versus a false alarm. One catch: weighting and resampling shift the predicted probabilities, so if the business uses them as real probabilities, I recalibrate afterwards."
Reporting accuracy on imbalanced data, or oversampling before the split so copies of a row land in both train and test.
Needs it: distance-based models (k-NN, k-means, SVM), anything trained by gradient descent, regularised models, PCA.
Doesn't: tree-based models, because splits only depend on the order of values.
Which: standardisation is the usual default; min-max when you need a fixed range; robust scaling with heavy outliers.
Rule: fit the scaler on the training data, then apply it to validation and test.
"Scaling matters whenever a model compares features by size. Distance-based models like k-nearest neighbours, k-means and SVMs will let a column in thousands swamp a column between zero and one. Gradient descent converges much faster when features are on similar scales. Regularised models need it so the penalty treats every weight fairly, and PCA needs it or it just picks the largest-unit column. Trees and tree ensembles don't care, because a split only depends on the order of the values. My default is standardisation, zero mean and unit variance. I use min-max when something needs a bounded range, and robust scaling based on the median when there are big outliers. The key rule is that I fit the scaler on training data only and reuse it everywhere else, ideally inside a pipeline."
Saying every model needs scaling, or fitting the scaler on the full dataset including the test rows.
Few values: one-hot encoding; ordinal encoding only if the order is real.
Many values: frequency or count encoding, hashing, or target encoding with smoothing.
Target encoding risk: compute it out of fold, or each row sees its own label and the model cheats.
Unseen values: decide up front how new categories at prediction time are handled.
"For a low-cardinality feature, like payment method with four values, I use one-hot encoding. Ordinal encoding is only right if the order means something, like small, medium, large, although tree models cope with arbitrary integer codes better than linear ones. For thousands of values, one-hot explodes the width and most columns are nearly empty. There I'd try frequency encoding, the hashing trick, or target encoding, where each category is replaced by the average target for that category. Target encoding is powerful but leaks badly if done naively, because each row's own label goes into its value. So I compute it out of fold and smooth rare categories toward the overall mean. I also plan for categories that appear only in production, mapping them to an unknown bucket."
Using label encoding with arbitrary integers in a linear model, or target encoding on the full data without folds.
Loss: mean squared error; its gradient is 2/n times X transpose times the residuals.
Update: subtract the learning rate times the gradient; add a bias column for the intercept.
Learning rate: too high diverges or bounces, too low crawls; try a few values on a log scale and watch the loss.
Variants: full batch is smooth but slow per step; stochastic and mini-batch are noisy but cheap and scale to big data.
"I add a column of ones so the intercept is just another weight, start the weights at zero, and loop. Each step I compute predictions, take the residuals, and the gradient of mean squared error is two over n times X transpose times the residuals. Then I step against the gradient, scaled by the learning rate. For the learning rate, I try a few values on a log scale, like 0.1, 0.01 and 0.001, and plot the loss. If it explodes or zigzags, it's too high; if it barely moves, it's too low. Scaling the features first helps a lot. Full-batch uses all rows per step, which is smooth but slow on big data. Mini-batch uses a small random chunk per step, which is noisier but far cheaper and is the usual choice in practice."
import numpy as np
def fit_linear_gd(X, y, lr=0.01, epochs=1000):
n, d = X.shape
Xb = np.hstack([np.ones((n, 1)), X]) # bias column
w = np.zeros(d + 1)
for _ in range(epochs):
residuals = Xb @ w - y
grad = (2 / n) * Xb.T @ residuals # gradient of MSE
w -= lr * grad
return w # w[0] is the intercept
Looping over rows in pure Python for the gradient, getting the sign of the update wrong, or forgetting the intercept.
Grid: tries every combination; fine for two or three small ranges, wasteful beyond that.
Random: samples combinations; covers important parameters better for the same budget.
Bayesian: uses past results to choose the next trial; best when each fit is expensive.
Honesty: tune on validation or cross-validation only; the test set is scored once at the end.
"I start by deciding which few hyperparameters actually matter for the model, like depth, learning rate and number of trees for boosting, and set sensible ranges, often on a log scale. Grid search tries every combination, which is fine for two small ranges but grows fast and wastes trials on settings that don't matter. Random search samples the space and, for the same budget, usually finds good values faster because it tries more distinct values of each parameter. When every fit is expensive, I use Bayesian optimisation, which builds a model of the score from past trials and picks promising next points. Whatever the method, I score with cross-validation or a validation set and use early stopping where I can. The test set stays untouched until the very end, or my final number is optimistic."
Tuning on the test set, or running a huge grid without first narrowing down which parameters matter.
Definition: the model sees information during training that it won't have at prediction time.
Target leakage: a feature recorded after, or because of, the outcome.
Split leakage: preprocessing fitted on all data, duplicates or the same user across splits, future rows in training.
Catching it: suspiciously good scores, one dominant feature, and asking 'when is this value known?' for every column.
"Leakage is when training data carries information the model won't have when it's actually used, so offline scores look great and production doesn't. The classic kind is target leakage: predicting loan default with a column like 'sent to collections', which only exists because the customer defaulted. The other kind comes from the split: fitting a scaler or imputer on all the data before splitting, having the same customer in both train and test, or randomly splitting time-ordered data so the model trains on the future. To catch it, I'm suspicious of any score that seems too good. I look at feature importances, and if one feature dominates, I ask exactly when that value gets recorded. I also put all preprocessing in a pipeline so it's fitted inside each fold, and split by time or by group when the data needs it."
Defining leakage only as 'test data in the training set' and missing features that are only known after the outcome.
ColumnTransformer: different steps for numeric and categorical columns.
Pipeline: preprocessing and model as one object, so cross-validation refits both on each training fold.
Validation: stratified folds and a metric that suits the problem; report mean and spread.
"I put the preprocessing and the model in one pipeline so nothing is fitted outside the training folds. A ColumnTransformer standardises the numeric columns and one-hot encodes the categorical ones, with unknown categories ignored so new values in the validation fold don't crash it. The pipeline chains that with logistic regression. Then I hand the whole pipeline to cross_val_score with stratified folds. On each fold, the scaler and encoder are fitted on the training part only and applied to the held-out part, exactly as they would be in production. I report the mean and standard deviation of the scores. The same pipeline object can go into a grid search, and at the end I fit it on all training data and save it as one artifact, so serving uses identical preprocessing."
from sklearn.compose import ColumnTransformer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import StratifiedKFold, cross_val_score
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
prep = ColumnTransformer([
("num", StandardScaler(), ["age", "income"]),
("cat", OneHotEncoder(handle_unknown="ignore"), ["city"]),
])
model = Pipeline([
("prep", prep),
("clf", LogisticRegression(max_iter=1000)),
])
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(model, X, y, cv=cv, scoring="roc_auc")
print(scores.mean(), scores.std())
Calling fit_transform on the whole dataset first and then cross-validating only the model.
Serving mode: batch scoring on a schedule or an online API, decided by how fresh predictions must be.
One artifact: version the preprocessing and model together, with the data and code that built them.
Feature parity: same feature code for training and serving, log served features, and test that they match.
Rollout: shadow or canary against the current system, monitoring in place, and a clear rollback.
"First I ask how fresh predictions need to be. If a daily score is enough, batch scoring into a table is simpler and cheaper than an online API. Then I package the preprocessing and model together as one versioned artifact, recording the training data snapshot and code version. The biggest risk is train-serve skew: a feature computed one way in a SQL training query and another way in the live service. So I make both paths use the same feature code or a shared feature store, log the exact features served with each prediction, and run a parity check comparing them against what the training pipeline would compute for the same entities. For rollout, I run it in shadow mode or on a small slice of traffic, compare against the current system, and keep a one-step rollback. Monitoring covers latency, errors, input distributions and, once labels arrive, accuracy."
Ending the answer at 'wrap it in an API', with no thought for feature consistency, versioning or rollback.
Data drift: the input distribution changes, like a new customer mix; the rules may still hold.
Concept drift: the relationship between inputs and target changes, like fraudsters changing tactics.
Monitoring: compare feature and prediction distributions to training (PSI, KS test); track real metrics once labels land.
Response: investigate before retraining; a broken upstream pipeline looks like drift too.
"Data drift means the inputs have shifted, say a marketing campaign brings in younger users, while the underlying rules might be the same. Concept drift means the relationship itself changed, so the same inputs now lead to different outcomes, like fraudsters changing their pattern after we blocked the old one. Data drift I can watch immediately: I compare each feature's live distribution and the prediction distribution against the training data, using something like the population stability index or a KS test, and alert on big moves. Concept drift usually only shows once labels arrive, so I track the real metric on recent labelled data. When an alert fires, I don't retrain blindly. Often the cause is an upstream bug, like a unit change or a column suddenly full of nulls, and retraining on that would bake the bug in."
Treating every drift alert as a reason to retrain automatically without checking whether the data pipeline broke.
Situation: the model, the offline score and what production showed instead.
Diagnosis: how you narrowed it down, with evidence, not guesses.
Fix: the change to the model or the pipeline.
Lesson: the check you now run on every project.
"At my last company I built a model to flag risky orders. Offline it separated good and bad orders really well, but in the first weeks live, it caught far fewer bad orders than we expected. I compared the features the live service had logged with what my training query produced for the same orders. One of the strongest features, the number of orders from that account in the last day, was computed from the full day of data in training, but in real time it only counted orders placed so far. So the model had learned from information it never had live. I rebuilt the feature so both paths used the same point-in-time logic, retrained, and results moved close to the offline numbers. Now I log served features from day one and run a parity check before any launch."
A story that blames 'the data' vaguely with no diagnosis steps, or one where the candidate never looked at production data themselves.
Symptom: the model plateaued or behaved strangely despite tuning.
Digging: what you looked at in the raw data or labels.
Fix: how you and the business corrected the data or the target definition.
Result: what improved, and what you do differently now.
"In a churn project, I spent a week trying different models and the score barely moved. So I stopped tuning and read through examples the model got confidently wrong. Many customers labelled as churned came back a few weeks later. Our label said a customer had churned if they didn't log in for seven days, which caught people on holiday or with a quiet month. I took examples to the customer success team, and together we agreed on a definition based on thirty days of no activity plus no active subscription. With the new label the model improved more than any tuning had, and the scores made sense to the people using them. Since then, I always read a sample of labels and wrong predictions before touching hyperparameters."
Claiming the model is always the lever, or a story where the candidate changed the label alone without agreeing it with the business.
Audience: who they were and what decision they needed to make.
Translation: metrics turned into outcomes they already track.
Honesty: what the model gets wrong and how to use it anyway.
Result: what they did with it.
"I built a model that ranked customers by how likely they were to cancel, for a retention team who'd never used a model before. They didn't care about AUC, so I didn't show it. I said, 'If you call the top two hundred customers on this list, about sixty of them would actually have left. If you picked two hundred at random, it would be around ten.' That made it concrete. I also showed three example customers and the main reasons the model flagged them, which built trust. And I was upfront that most people on the list wouldn't leave, so calls should feel like a check-in, not a rescue. They started with the top of the list each week, and I added a simple sheet showing how their saves compared with a random group."
Presenting AUC or F1 to a business audience without translating it into outcomes they can act on.
Tell people: flag it to your lead before the review, not after.
Quantify: say the number is optimistic and, if possible, by how much.
Fresh estimate: find data the model never touched, like a newer time window, and score once.
Prevent: lock the test set away and use cross-validation for tuning next time.
"First, I'd tell my lead that evening, before anyone sees the slide. Presenting that number as a clean estimate would be misleading, and it's much worse if someone finds it later. Then I'd look for a fair number fast. Often there's newer data the model has never seen, like the most recent few weeks, and I'd score the model on it once. If there isn't, I'd re-run the tuning with cross-validation on the training data only and report that, clearly labelled. In the review I'd show the honest number and say plainly what happened, which usually earns more trust than it costs. Afterwards I'd set up the project so the test set lives in a separate place and is only read by a final evaluation script."
Presenting the number anyway and planning to 'fix it later', or quietly swapping in a new split without telling anyone.
Clarify: what 'explain' must mean here; a legal requirement differs from a nice-to-have.
Size the gain: turn the small margin into outcomes the business feels.
Options: simpler model, explanation tools on the complex one, or constraints that keep it predictable.
Decide together: with the business and whoever owns compliance, and write the reasoning down.
"I'd start by finding out what 'explain' has to mean. If there's a legal or policy requirement to give customers clear reasons, that's a hard constraint, and I'd check it with whoever owns compliance. Then I'd translate the small margin into real terms, like how many more good decisions per ten thousand applications. If that gain is small and explanations must be exact and consistent, I'd ship the logistic regression, where each factor's effect is visible. If the gain is meaningful, I'd look at options like adding monotonic constraints to the boosting model so it behaves sensibly, and using per-decision explanations such as SHAP values, then check with the business whether those explanations are good enough for customers. Either way it's a joint decision, and I'd write down why we chose it."
Shipping the higher-scoring model by default without asking what the explanation requirement actually is.
Confirm: check the gap is real, with enough examples in that group, not noise.
Cause: fewer training examples, missing features, or a different pattern in that group.
Options: fix and delay, launch with a fallback for that group, or launch with monitoring and a date for the fix.
Decide openly: share the numbers and trade-offs with the product owner and record the decision.
"First I'd make sure the gap is real and not noise from a small sample, by checking how many examples that group has and how stable the gap is across folds. Then I'd look for the cause. New customers, for example, often have little history, so the features the model leans on are mostly empty. That points to fixes like a simpler model or rules for that group, or adding features that don't depend on history. Then I'd take the numbers to the product owner with options: delay the launch to fix it, launch but route that group to the current system, or launch with close monitoring and a date for a fix. What I wouldn't do is launch quietly and hope nobody notices, especially if the weaker results could treat people unfairly."
Looking only at the overall metric and saying the average is fine, so the launch should go ahead unchanged.
ClapAssist is an AI interview assistant for Mac and Windows. It listens to the interview on your computer and shows you what to say, in short lines you can read while you talk. Your resume and notes are never stored on our servers. It stays out of screen share on every plan; only you can see it.