Machine learning interview questions: a practical guide
If you've shipped machine learning models to production, you know the difference between textbook theory and what actually works. Interview questions that probe this gap separate candidates who understand the mechanics from those who can build reliable systems. This guide walks through the questions we ask senior engineers when hiring for ML-heavy roles, and what answers tell us they've learned from real-world mistakes.
Bias-variance trade-off
This question almost always appears because it cuts to the heart of model tuning. The bias-variance trade-off describes a fundamental tension: bias is error from oversimplified assumptions (underfitting), while variance is error from sensitivity to training data noise (overfitting). Neither alone is the enemy; the real skill is recognizing which problem you're facing and what to do about it.
A production answer sounds like this: "I fit a linear regression to a nonlinear problem and got consistently poor predictions on both train and test sets—high bias. I then added polynomial features and cross-validation revealed my model started memorizing noise in small regions of the input space, indicating high variance. I used regularization (L2 penalty) to constrain the model, which traded a small increase in bias for a large decrease in variance, improving test performance overall."
The key is concrete diagnosis. We look for evidence they've actually run learning curves (training and validation error plotted against dataset size or model complexity), not just recited the definition. If training error stays high as you add data, bias dominates. If training error is low but validation error climbs, variance dominates.
import numpy as np
from sklearn.model_selection import learning_curve
from sklearn.linear_model import Ridge
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
# Generate synthetic nonlinear data
X = np.linspace(-3, 3, 100).reshape(-1, 1)
y = np.sin(X).ravel() + np.random.normal(0, 0.1, 100)
# Low-bias, high-variance model: high-degree polynomial
model_hv = Pipeline([
('poly', PolynomialFeatures(degree=10)),
('ridge', Ridge(alpha=1e-8))
])
# Low-variance, higher-bias model: regularized
model_lb = Pipeline([
('poly', PolynomialFeatures(degree=10)),
('ridge', Ridge(alpha=10))
])
train_sizes, train_scores_hv, val_scores_hv = learning_curve(
model_hv, X, y, cv=5, scoring='neg_mean_squared_error'
)
train_sizes, train_scores_lb, val_scores_lb = learning_curve(
model_lb, X, y, cv=5, scoring='neg_mean_squared_error'
)
print("High variance model - train MSE:", -train_scores_hv.mean())
print("High variance model - val MSE:", -val_scores_hv.mean())
print("Low variance model - train MSE:", -train_scores_lb.mean())
print("Low variance model - val MSE:", -val_scores_lb.mean())
In real projects, we've seen teams spend weeks tuning hyperparameters when the root problem was bias—they needed better features or a more expressive model class, not more regularization.
Precision vs recall and when each matters
Precision (true positives divided by all predicted positives) answers "of the cases we flagged, how many were actually positive?" Recall (true positives divided by all actual positives) answers "of all the positive cases, how many did we catch?" A strong answer names the business cost of false positives versus false negatives and tailors the metric accordingly.
A weak answer is "precision for this project, recall for that one" without reasoning. A strong answer is "we optimized for recall in fraud detection because missing a fraudulent transaction costs us money and customer trust, while a false positive just triggers a verification step. In our lending model, we optimized precision because falsely labeling someone as high-risk damages their credit file, which is a legal and ethical problem."
We also look for awareness of the threshold. In most ML libraries, you output probabilities and then choose a decision boundary (typically 0.5). Sliding that threshold trades off precision and recall. At 0.3, you catch more positive cases (high recall) but flag more false alarms (low precision). At 0.7, you flag only confident cases (high precision) but miss some true positives (lower recall).
from sklearn.metrics import precision_recall_curve, roc_auc_score
import numpy as np
# Simulated fraud detection: predicted probabilities and true labels
y_true = np.array([0, 0, 1, 1, 0, 1, 0, 0, 1, 1])
y_proba = np.array([0.1, 0.4, 0.85, 0.92, 0.3, 0.78, 0.2, 0.5, 0.88, 0.95])
precisions, recalls, thresholds = precision_recall_curve(y_true, y_proba)
# Find threshold that balances precision and recall (or prioritize one)
f1_scores = 2 * (precisions * recalls) / (precisions + recalls + 1e-8)
best_idx = np.argmax(f1_scores)
best_threshold = thresholds[best_idx]
print(f"Best F1 threshold: {best_threshold:.2f}")
print(f"Precision at best F1: {precisions[best_idx]:.2f}")
print(f"Recall at best F1: {recalls[best_idx]:.2f}")
# Or choose threshold manually based on business logic
high_recall_threshold = 0.3
high_precision_threshold = 0.7
The F1 score (harmonic mean of precision and recall) is useful when you want to balance both, but it's not always the right choice. We avoid defaulting to it without understanding the cost structure of your errors.
How to detect data leakage
Data leakage is when information from outside the training set sneaks into the model in a way that doesn't reflect what will be available at prediction time. It's insidious because it makes your offline metrics look fantastic while your production model fails silently. Detecting it requires systematic thinking about data pipelines.
A concrete example: we built a churn prediction model using a feature that counted "days since last support ticket." On the training set, this feature was incredibly predictive—customers who churned had fewer recent support tickets. But at prediction time, we're trying to forecast churn for customers who are still active. For them, this feature looks into the future (we can't know their support behavior next month). The model trained on historical data where churn was known, so it picked up a correlation that doesn't transfer forward in time.
To catch this, we ask: "What information would actually be available at prediction time?" If your feature requires knowledge of the future target or of events that only become observable after the label is determined, it's leaked. Common culprits include:
- Time-based leakage: using information from dates after the prediction date.
- Target leakage: features derived directly from the target variable.
- Test set statistics: fitting a scaler on train+test data, then using it on both (the test set has influenced preprocessing).
- Aggregation leakage: grouping by a column that includes the prediction label (e.g., computing mean purchase value grouped by "customer churned or not").
Prevention is stricter than detection. Split your data by time if it's temporal data. Fit all preprocessing (scaling, encoding, imputation) only on the training set, then transform test and production data with those learned parameters. Use a separate held-out test set that you touch as few times as possible.
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import pandas as pd
# Wrong: fit scaler on train + test together
X = pd.DataFrame({'feature': [1, 2, 3, 4, 5, 6]})
y = pd.Series([0, 0, 1, 1, 0, 1])
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33)
# Leakage: scaler learned from both sets
scaler_wrong = StandardScaler()
scaler_wrong.fit(pd.concat([X_train, X_test]))
X_train_scaled_wrong = scaler_wrong.transform(X_train)
X_test_scaled_wrong = scaler_wrong.transform(X_test)
# Correct: fit scaler only on training data
scaler_correct = StandardScaler()
scaler_correct.fit(X_train)
X_train_scaled = scaler_correct.transform(X_train)
X_test_scaled = scaler_correct.transform(X_test) # transform, don't fit
print("Train mean (correct):", X_train_scaled.mean())
print("Test mean (correct):", X_test_scaled.mean())
# Test mean will likely be non-zero: this is expected and correct
We also ask candidates how they'd validate their pipeline didn't leak. A solid answer: "I'd train the model on data from month 1-3, evaluate on month 4, then train on months 1-4 and evaluate on month 5. If performance degrades significantly moving forward in time, there's likely leakage. I'd also inspect feature importances—if a feature that shouldn't be available at prediction time ranks high, that's a red flag."
How to handle imbalanced classes
In many real problems, your positive class is rare. Fraud, equipment failure, disease diagnosis—these are often 1-10% of your data. A naive model that predicts "no fraud" for every transaction will have 99% accuracy and be worthless. Handling imbalance is both technical and strategic.
The technical options:
- Resampling: Oversample the minority class (duplicate examples or generate synthetic ones via SMOTE) or undersample the majority class (discard majority examples). Each has trade-offs: oversampling can lead to overfitting; undersampling throws away data.
- Class weights: Tell your loss function to penalize errors on the minority class more heavily. Most scikit-learn models accept
class_weight='balanced', which automatically weights classes inversely to their frequency. - Threshold adjustment: Train on the imbalanced data but raise the probability threshold required to predict the minority class, effectively tuning recall.
- Different metrics: Use precision-recall curves, F1 score, or ROC-AUC instead of accuracy.
The strategic part is understanding your business. If the minority class has higher cost (fraud is worse than false alarms), you can afford to chase recall even at the cost of precision. If you're limited in how many cases you can manually review, precision might matter more. We've seen projects fail because they optimized for the wrong metric on imbalanced data.
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import f1_score, precision_recall_curve
import numpy as np
# Highly imbalanced dataset
X, y = make_classification(
n_samples=1000, n_features=20, n_informative=10,
weights=[0.95, 0.05], random_state=42
)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
# Without class weighting
model_unweighted = LogisticRegression(max_iter=1000)
model_unweighted.fit(X_train, y_train)
y_pred_uw = model_unweighted.predict(X_test)
f1_uw = f1_score(y_test, y_pred_uw)
# With class weighting
model_weighted = LogisticRegression(
max_iter=1000, class_weight='balanced'
)
model_weighted.fit(X_train, y_train)
y_pred_w = model_weighted.predict(X_test)
f1_w = f1_score(y_test, y_pred_w)
print(f"F1 without weighting: {f1_uw:.3f}")
print(f"F1 with weighting: {f1_w:.3f}")
# Even better: tune the threshold
y_proba = model_weighted.predict_proba(X_test)[:, 1]
precisions, recalls, thresholds = precision_recall_curve(y_test, y_proba)
f1_scores = 2 * (precisions * recalls) / (precisions + recalls + 1e-8)
best_threshold = thresholds[np.argmax(f1_scores)]
print(f"Optimal threshold: {best_threshold:.3f}")
Common mistakes
Candidates often confuse precision and recall or name them backward. Others recite textbook definitions without connecting them to a real project. We've heard "just use accuracy" from engineers who've never worked on imbalanced data. The weakest answer is avoiding the question entirely or saying "I always use cross-validation"—that's necessary but doesn't address the core issue. The worst is claiming you'd use the same approach for every problem; good engineering is about fit-for-purpose solutions.
Another common gap: assuming that better offline metrics guarantee better production performance. Candidates who've dealt with data leakage or distribution shift know this isn't true. They discuss monitoring, shadow deployments, and held-out test sets that you don't touch until the model is in production.
Key takeaways
- Bias-variance trade-off is about diagnosis: use learning curves to identify whether your model underfits or overfits, then adjust accordingly.
- Precision and recall have different business meanings; choose your metric based on the cost of false positives versus false negatives, not default to accuracy.
- Data leakage is prevented by thinking through what information is available at prediction time, fitting preprocessing only on training data, and validating performance across time periods.
- Imbalanced classes require both technical solutions (class weights, resampling, threshold tuning) and strategic thinking about which errors matter most.
- The strongest answers tie theory to production experience and acknowledge trade-offs rather than claiming one approach works everywhere.






Comments
Loading comments…