ML Fundamentals Interview Questions and Answers
41 hand-picked ML Fundamentals interview questions with
detailed answers. Open the interactive version above to search, filter
by difficulty, run code, bookmark questions and track your progress.
Supervised vs unsupervised vs reinforcement learning.
- Supervised — learn from labelled data (input → known output). Tasks: classification, regression. Example: spam detection, house price prediction.
- Unsupervised — find patterns in unlabelled data. Tasks: clustering, dimensionality reduction, anomaly detection. Example: customer segmentation.
- Reinforcement — agent learns by interacting with an environment, receiving rewards/penalties. Example: game playing, robotics, RLHF for LLM alignment.
Training vs inference in machine learning.
Training — the model learns patterns from data by adjusting weights to minimise a loss function. Computationally expensive; done offline or periodically.
Inference — using the trained model to make predictions on new, unseen data. Must be fast and reliable for production serving.
Training uses backward propagation and optimisers (Adam, SGD). Inference is forward-pass only.
Classification vs regression.
Classification — predict a category (discrete label). Binary (spam/not spam) or multi-class (cat/dog/bird). Output: class probabilities.
Regression — predict a continuous number. Example: house price, temperature, revenue forecast. Output: a real-valued number.
Same algorithms can do both with different loss functions and output layers.
Overfitting vs underfitting.
Overfitting — model memorises training data (including noise) and fails on new data. Signs: high training accuracy, low validation accuracy. Fixes: more data, regularisation, simpler model, dropout, early stopping.
Underfitting — model is too simple to capture patterns. Signs: poor performance on both training and validation. Fixes: more features, complex model, train longer.
Goal: generalisation — good performance on unseen data.
Explain the bias-variance tradeoff.
Total prediction error = bias² + variance + irreducible noise.
- High bias (underfitting) — model is too simple, makes systematic errors. Low training AND validation error gap, but both are high.
- High variance (overfitting) — model is too sensitive to training data fluctuations. Low training error, high validation error.
Increasing model complexity reduces bias but increases variance — find the sweet spot.
Why split data into train, validation, and test sets?
- Training set (~70-80%) — model learns from this.
- Validation set (~10-15%) — tune hyperparameters, select model architecture, decide when to stop training.
- Test set (~10-15%) — final unbiased evaluation, touched once at the end.
Using test data during development causes data leakage — you overfit to the test set indirectly.
from sklearn.model_selection import train_test_split
X_train, X_temp, y_train, y_temp = train_test_split(X, y, test_size=0.3)
X_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp, test_size=0.5)
What is k-fold cross-validation?
Split data into k folds. Train on k-1 folds, validate on the remaining fold. Repeat k times, each fold serving as validation once. Average the k scores for a robust performance estimate.
Useful when data is limited — every sample gets to be in both training and validation. Common: k=5 or k=10.
Stratified k-fold preserves class distribution in each fold (important for imbalanced data).
from sklearn.model_selection import cross_val_score
scores = cross_val_score(model, X, y, cv=5, scoring='f1')
print(scores.mean(), scores.std())
Common loss functions and when to use them.
- MSE / MAE — regression. MSE penalises large errors more; MAE is robust to outliers.
- Cross-entropy / log loss — classification. Measures distance between predicted probabilities and true labels.
- Hinge loss — SVM classification.
- Focal loss — classification with class imbalance; down-weights easy examples.
The loss function defines what 'wrong' means — choose one aligned with your business metric.
What is gradient descent?
An optimisation algorithm that iteratively adjusts model weights in the direction that reduces the loss (opposite to the gradient).
- Batch GD — uses entire dataset per step; accurate but slow.
- Stochastic GD (SGD) — one sample per step; noisy but fast.
- Mini-batch GD — compromise; batch of 32–256 samples. Standard in deep learning.
- Adam — adaptive learning rate; default optimiser for most neural nets.
How does a neural network work at a high level?
A network of layers of neurons connected by weighted edges:
- Input layer — receives features.
- Hidden layers — transform inputs through weighted sums + activation functions, learning hierarchical features.
- Output layer — produces predictions (softmax for classification, linear for regression).
Training: forward pass (compute output) → compute loss → backward pass (backpropagation computes gradients) → update weights.
Common activation functions and their roles.
- ReLU —
max(0, x). Default for hidden layers. Fast, avoids vanishing gradient. Dead ReLU problem (neurons output 0 forever). - Sigmoid — squashes to (0,1). Used for binary classification output. Vanishing gradient in deep networks.
- Softmax — multi-class output; probabilities sum to 1.
- Tanh — squashes to (-1,1). Sometimes used in hidden layers.
- GELU / Swish — smooth variants used in transformers (BERT, GPT).
CNN vs RNN vs Transformer — when to use each?
| Architecture | Strength | Typical use |
|---|
| CNN | Spatial/local patterns via convolutions | Image classification, object detection, medical imaging |
| RNN/LSTM | Sequential data, temporal dependencies | Time series, early NLP (largely replaced) |
| Transformer | Long-range dependencies, parallel training | NLP, vision (ViT), multimodal, LLMs |
Transformers dominate NLP and are increasingly used for vision, audio, and tabular data too.
What is feature engineering and why does it matter?
Transforming raw data into informative inputs the model can learn from. Examples:
- Normalising/scaling numerical features (StandardScaler, MinMaxScaler)
- Encoding categoricals (one-hot, label encoding, target encoding)
- Creating derived features (age from birthdate, day-of-week from timestamp)
- Handling missing values (imputation, indicator columns)
- Text: TF-IDF, tokenisation (or use embeddings for deep learning)
Deep learning reduces manual feature engineering but preprocessing still matters.
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test) # use train stats!
Precision, recall, and F1 score.
- Precision — of predicted positives, how many are actually positive?
TP / (TP + FP). "When I say yes, how often am I right?" - Recall — of actual positives, how many did I catch?
TP / (TP + FN). "Of all real positives, how many did I find?" - F1 — harmonic mean of precision and recall. Balances both.
Choose based on cost: spam filter needs high precision (don't block real emails); cancer screening needs high recall (don't miss cases).
from sklearn.metrics import precision_score, recall_score, f1_score
print(f1_score(y_true, y_pred))
How do you read a confusion matrix?
A table comparing predicted vs actual labels:
Predicted
Pos Neg
Actual Pos TP FN
Neg FP TN
- TP — correctly predicted positive
- FP — false alarm (Type I error)
- FN — missed positive (Type II error)
- TN — correctly predicted negative
All classification metrics derive from these four counts.
from sklearn.metrics import confusion_matrix
print(confusion_matrix(y_true, y_pred))
What is ROC-AUC?
ROC curve — plots True Positive Rate (recall) vs False Positive Rate at various classification thresholds.
AUC (Area Under Curve) — single number summarising ROC. 1.0 = perfect; 0.5 = random guessing.
Threshold-independent metric — useful for comparing models regardless of the chosen decision threshold. Good for imbalanced datasets when you haven't decided on a threshold yet.
from sklearn.metrics import roc_auc_score
auc = roc_auc_score(y_true, y_prob) # needs probability scores, not class labels
How do you tune hyperparameters?
Hyperparameters are set before training (learning rate, tree depth, number of layers) — not learned from data.
Methods:
- Grid search — try all combinations from a predefined grid. Exhaustive but expensive.
- Random search — sample random combinations. Often finds good configs faster than grid.
- Bayesian optimisation — model the objective function; sample intelligently (Optuna, Hyperopt).
Always tune on validation set, evaluate final config on test set.
from sklearn.model_selection import GridSearchCV
grid = GridSearchCV(model, param_grid, cv=5, scoring='f1')
grid.fit(X_train, y_train)
print(grid.best_params_)
What is transfer learning?
Using a model pre-trained on a large dataset as a starting point for your specific task. Instead of training from scratch, you fine-tune the last layers (or the whole model) on your smaller dataset.
Examples: ImageNet-pretrained ResNet for medical imaging; BERT/GPT for NLP tasks; Whisper for speech.
Saves data, compute, and time — almost always better than training from scratch on small datasets.
from transformers import AutoModelForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained(
"bert-base-uncased", num_labels=3
)
What is data leakage and how do you prevent it?
When information from outside the training set leaks into training, giving unrealistically good evaluation metrics that don't hold in production.
Common causes:
- Fitting scaler/encoder on full dataset before splitting
- Using future data to predict the past (time series)
- Target leakage — a feature that directly encodes the label
- Duplicate records across train and test
Fix: split first, then preprocess. Use pipelines. Audit features for leakage.
from sklearn.pipeline import Pipeline
pipe = Pipeline([
('scaler', StandardScaler()),
('model', LogisticRegression())
])
pipe.fit(X_train, y_train) # scaler fits only on train
How do you handle imbalanced datasets?
- Right metrics — use F1, precision-recall, AUC — not accuracy.
- Class weights — penalise misclassifying the minority class more (
class_weight='balanced'). - Oversampling — duplicate minority samples (SMOTE generates synthetic ones).
- Undersampling — reduce majority class (loses data).
- Threshold tuning — adjust decision threshold to favour recall or precision.
- Ensemble methods — combine models trained on balanced subsets.
from sklearn.utils.class_weight import compute_class_weight
weights = compute_class_weight('balanced', classes=np.unique(y), y=y)
What are ensemble methods?
Combine multiple models for better performance than any single model:
- Bagging — train many models on random subsets, average predictions. Example: Random Forest (bagged decision trees).
- Boosting — train models sequentially, each correcting previous errors. Examples: XGBoost, LightGBM, CatBoost.
- Stacking — train a meta-model on base model predictions.
Gradient boosted trees dominate tabular data competitions and production ML.
import xgboost as xgb
model = xgb.XGBClassifier(n_estimators=100, max_depth=6)
model.fit(X_train, y_train)
L1 vs L2 regularization.
Both add a penalty term to the loss function to prevent large weights:
- L1 (Lasso) — penalty = λΣ|w|. Drives some weights to exactly zero → feature selection. Sparse models.
- L2 (Ridge) — penalty = λΣw². Shrinks weights toward zero but rarely to exactly zero. Smoother models.
- Elastic Net — combines L1 + L2.
In neural nets, L2 regularisation is called weight decay.
from sklearn.linear_model import Lasso, Ridge
lasso = Lasso(alpha=0.1) # L1
ridge = Ridge(alpha=1.0) # L2
What is batch normalization?
Normalises the inputs to each layer during training — zero mean, unit variance within each mini-batch. Reduces internal covariate shift (changing input distributions as earlier layers update).
Benefits: faster training, allows higher learning rates, acts as mild regularisation. Standard in CNNs and feedforward networks. Layer Normalisation is preferred in transformers (normalises across features, not batch).
import torch.nn as nn
layer = nn.Sequential(
nn.Linear(256, 128),
nn.BatchNorm1d(128),
nn.ReLU()
)
What is MLOps and why does it matter?
MLOps applies DevOps principles to ML: reproducible training, automated deployment, monitoring, and retraining.
Key practices:
- Version everything — data, code, model weights, configs (MLflow, DVC).
- CI/CD for models — automated testing, validation gates before deployment.
- Model serving — REST/gRPC endpoints, batch inference, edge deployment.
- Monitoring — track prediction drift, data drift, latency, error rates.
- Retraining pipelines — trigger when performance degrades or new data arrives.
Linear regression vs logistic regression.
Linear regression predicts a continuous number. It fits y = wx + b by minimising mean squared error; output is unbounded.
Logistic regression predicts a probability for a class. It passes the same linear combination through a sigmoid to squash it into (0, 1), and trains with log loss (cross-entropy) rather than MSE.
Despite the name, logistic regression is a classifier. It's linear in the sense that the decision boundary is a straight line/hyperplane — which is exactly its limitation on non-linearly-separable data.
Both remain strong baselines: fast, interpretable coefficients, and hard to beat on small tabular datasets with mostly linear signal.
How does a decision tree work, and what are its weaknesses?
The tree greedily picks, at each node, the feature and threshold that best separates the data — measured by Gini impurity or entropy (information gain) for classification, variance reduction for regression — and recurses until a stopping rule fires.
Strengths: no scaling needed, handles mixed numeric/categorical data, captures non-linear interactions, and the path to a prediction is human-readable.
Weaknesses: a single deep tree overfits badly and is unstable — small data changes give a very different tree. It also produces axis-aligned, staircase boundaries, and biases splits toward high-cardinality features.
Controlled by max_depth, min_samples_leaf, min_samples_split and pruning — but the real fix for the variance is ensembling.
Random Forest vs Gradient Boosting — how do they differ?
Both are tree ensembles; they attack opposite ends of the bias-variance decomposition.
- Random Forest (bagging) — many deep trees trained in parallel on bootstrap samples, each split considering a random feature subset. Averaging cancels variance. Robust, hard to overfit by adding trees, very few knobs.
- Gradient Boosting (XGBoost / LightGBM / CatBoost) — many shallow trees trained sequentially, each fitting the residual errors of the ensemble so far. Reduces bias. Usually the top performer on tabular data, but it can overfit with too many rounds and needs tuning (learning rate, depth, subsampling, early stopping).
Rule of thumb: Random Forest for a fast, safe baseline; gradient boosting when you want the best tabular score and can afford to tune.
Normalization vs standardization — and which models need them?
- Min-max normalization → rescales to [0, 1]. Preserves the shape of the distribution but is sensitive to outliers.
- Standardization (z-score) → mean 0, standard deviation 1. The usual default; handles outliers better and is what most algorithms assume.
- Robust scaling → uses median and IQR; best when outliers are heavy.
Needed by: anything distance- or gradient-based — KNN, SVM, K-means, PCA, logistic/linear regression with regularisation, and neural networks.
Not needed by: tree-based models (trees split on thresholds, so monotonic rescaling changes nothing).
Critical detail: fit the scaler on the training set only, then apply it to validation and test. Fitting on the full dataset leaks test statistics into training.
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
# scaler is fit inside each CV fold -> no leakage
pipe = Pipeline([
("scale", StandardScaler()),
("clf", LogisticRegression()),
])
pipe.fit(X_train, y_train)
How do you encode categorical features?
- One-hot — a binary column per category. Safe default for low cardinality (< ~15). Explodes dimensionality otherwise.
- Ordinal/label — map to integers. Correct only when the categories genuinely have an order (small < medium < large); otherwise it invents a false ordering that linear models will believe. Trees tolerate it.
- Target/mean encoding — replace the category with the mean target for that category. Powerful for high cardinality, but leaks the target unless computed out-of-fold with smoothing for rare categories.
- Frequency/count encoding — cheap, often surprisingly effective.
- Embeddings — learned dense vectors, standard for very high cardinality in neural nets.
Also handle the unseen category at inference — every scheme needs a defined fallback, or production breaks on the first new value.
How do you handle missing data?
First ask why it's missing — the mechanism decides the fix:
- MCAR (missing completely at random) — dropping rows is unbiased, just wasteful.
- MAR — missingness depends on other observed features; model-based imputation works.
- MNAR — missingness depends on the unobserved value itself (income missing because it's high). Imputation biases the model; the fact of missingness is signal.
Techniques: drop (only if few rows or a mostly-empty column), mean/median/mode (simple, shrinks variance), forward-fill for time series, KNN or iterative imputation (MICE), or let the model handle it natively — LightGBM and XGBoost learn a default direction for missing values.
Almost always worth adding an explicit was_missing indicator column: it preserves the signal that imputation destroys.
What is the curse of dimensionality?
As the number of features grows, the volume of the space grows exponentially, so your fixed number of samples becomes vanishingly sparse in it. Consequences:
- Distance stops discriminating — in high dimensions the nearest and farthest neighbours have nearly the same distance, which breaks KNN, K-means and anything similarity-based.
- Data requirements explode — covering the space needs exponentially more samples.
- Overfitting gets easy — with enough features you can separate any training set by coincidence.
Countermeasures: feature selection, dimensionality reduction (PCA, UMAP), regularisation (L1 drives features to zero), domain-driven feature engineering, and using models that cope better with many features (regularised linear models, tree ensembles).
Note embeddings are the constructive flip side: they map sparse high-dimensional data into a dense low-dimensional space where distance is meaningful again.
What is PCA and when do you use it?
Principal Component Analysis finds the orthogonal directions of maximum variance in the data and re-expresses it in those axes. Keeping the top k components gives a lower-dimensional representation that preserves as much variance as possible.
Use it for: compressing correlated features, removing multicollinearity before a linear model, speeding up training, and 2-D visualisation of high-dimensional data.
Costs: components are linear combinations of all original features, so you lose interpretability; it is unsupervised, so a low-variance direction that happens to be the one predictive of your label can be discarded; and it only captures linear structure.
Requirements: standardize first (PCA follows variance, so unscaled large-unit features dominate), and fit on the training set only.
How does K-means work and what are its limitations?
Pick k centroids, then repeat until stable: assign each point to the nearest centroid, then move each centroid to the mean of its assigned points. It minimises within-cluster variance (inertia).
Limitations:
- You must choose k — use the elbow curve or silhouette score, both of which are heuristics.
- Assumes spherical, similar-sized clusters — fails on elongated, nested or density-varying shapes.
- Sensitive to initialisation — mitigated by k-means++ and multiple restarts.
- Sensitive to scale and outliers — standardize first; a single far point drags a centroid.
Alternatives: DBSCAN (density-based — finds arbitrary shapes, chooses its own cluster count, labels outliers as noise), hierarchical clustering (dendrogram, no k up front), GMM (soft assignments, elliptical clusters).
How does K-Nearest Neighbours work?
No training phase at all — it stores the dataset. To predict, it finds the k closest training points and takes a majority vote (classification) or mean (regression). This makes it a lazy, non-parametric, instance-based learner.
k controls the bias-variance trade: k=1 gives a jagged, high-variance boundary that memorises noise; large k over-smooths toward the majority class. Odd k avoids ties in binary classification.
Costs: prediction is O(n·d) per query, memory holds the whole dataset, features must be scaled, and it degrades badly in high dimensions.
It stays relevant conceptually because vector search is KNN — a RAG retriever is approximate KNN over embeddings, with an ANN index replacing the brute-force scan.
What is an SVM and what is the kernel trick?
A Support Vector Machine finds the hyperplane that separates classes with the maximum margin — the widest possible gap. Only the points on the margin (the support vectors) determine the boundary; everything else could be deleted without changing it.
C controls the soft-margin trade-off: high C means few misclassifications but a narrow margin (overfit risk); low C accepts errors for a wider, more general margin.
The kernel trick: for non-linearly-separable data, an SVM can operate as if the data were mapped into a much higher-dimensional space — but the algorithm only ever needs inner products, and a kernel function (RBF, polynomial) computes those directly without ever constructing the high-dimensional coordinates. You get a non-linear boundary at linear-ish cost.
Strong on small-to-medium, high-dimensional data (classic text classification). Scales poorly past ~100k rows and gives no calibrated probabilities by default.
How does Naive Bayes work, and why does it work despite its assumption?
It applies Bayes' theorem — P(class | features) ∝ P(class) · P(features | class) — with the "naive" assumption that features are conditionally independent given the class, so the joint likelihood factorises into a simple product.
That assumption is essentially always false (in text, words are highly correlated). It still works because classification only needs the correct class to score highest, not the probabilities to be accurate. The estimated probabilities are usually badly calibrated — over-confident near 0 and 1 — while the ranking survives.
Strengths: trains in one pass, needs little data, handles very high dimensions, excellent baseline for text (spam filtering, topic classification).
Practicalities: use Laplace smoothing so an unseen word doesn't zero out an entire product, and work in log-space to avoid floating-point underflow.
SGD, Momentum, Adam — how do optimizers differ?
- SGD — step against the gradient of a mini-batch. Simple, and with a good schedule it often generalises best, but it's slow and oscillates in ravines.
- Momentum — accumulate a velocity term so consistent gradient directions build speed and oscillations cancel. Like a ball rolling downhill.
- RMSProp — divide by a running average of squared gradients, giving each parameter its own effective learning rate. Helps when gradient scales differ wildly.
- Adam — momentum + RMSProp together, with bias correction. The default: fast convergence and forgiving of the initial learning rate.
- AdamW — Adam with weight decay decoupled from the gradient update, which is what standard Adam got subtly wrong. The default for transformers.
Learning-rate schedule usually matters more than optimizer choice: warmup then cosine decay is the common recipe.
What are vanishing and exploding gradients, and how are they fixed?
Backpropagation multiplies gradients layer by layer. If the per-layer factors are consistently < 1 the product shrinks toward zero — early layers stop learning (vanishing). If they're consistently > 1 it blows up to NaN (exploding). Depth makes both worse; sigmoid/tanh saturate and make vanishing much worse.
Fixes that made deep networks trainable:
- ReLU-family activations — gradient of 1 for positive inputs, no saturation.
- Residual (skip) connections — gradients get a direct path back; the key reason 100+ layer networks train at all.
- Normalization layers — BatchNorm/LayerNorm keep activation scales stable.
- Careful initialisation — He for ReLU, Xavier/Glorot for tanh, to keep variance constant across layers.
- Gradient clipping — the standard direct fix for explosion, especially in RNNs and transformer training.
What is dropout and how does it regularise a network?
During training, randomly zero each neuron's output with probability p (typically 0.2–0.5). During inference, dropout is switched off and activations are scaled so expected values match (frameworks do this via inverted dropout at train time).
Why it works: no neuron can rely on any specific other neuron being present, so the network can't build fragile co-adapted paths and is forced to learn redundant, distributed representations. It also approximates training an ensemble of exponentially many sub-networks that share weights.
Practical notes: apply it to dense layers rather than convolutional ones (which have their own variants); it interacts awkwardly with BatchNorm, so modern architectures often prefer one or the other; and transformers use it lightly, mostly on attention and residual paths.
What is model drift and how do you detect it?
A deployed model degrades because the world moved, not because the code changed.
- Data drift (covariate shift) — the input distribution changes: a new user segment, a new device type, an upstream schema change.
- Concept drift — the relationship between inputs and target changes: fraud tactics evolve, so the same features now mean something different.
- Label drift — the target distribution itself shifts.
Detection: monitor input feature distributions (PSI, KL divergence, Kolmogorov–Smirnov) and prediction distributions — these are available immediately. Actual accuracy needs ground truth, which often arrives days or months later, so drift metrics are your early warning.
Response: alert thresholds, scheduled or triggered retraining, and always keep a champion/challenger comparison so you can prove the retrained model is actually better before promoting it.
How do you explain a model's predictions? (SHAP, LIME, feature importance)
- Built-in feature importance (tree gain/split counts) — global, free, but biased toward high-cardinality features and says nothing about direction.
- Permutation importance — shuffle a feature and measure the score drop. Model-agnostic and more honest, but misleading when features are correlated.
- SHAP — game-theoretic Shapley values attributing each prediction to each feature, with a consistent additive guarantee. Works globally and per-prediction; the practical standard, though slow on large data (TreeSHAP is the fast path).
- LIME — fits a simple local surrogate around one prediction. Fast and intuitive, but less stable across runs.
- Partial dependence / ICE plots — show how the prediction moves as one feature varies.
Two cautions: explanations are correlational, not causal, and required by regulation in some domains (credit, hiring) — where an inherently interpretable model may be the safer choice than a post-hoc explanation of a black box.