Assumptions you are given
Fixed for every task. Several are choices a real team would have to justify, and questioning them is worth marks.
| # | Assumption | Consequence for your model |
|---|---|---|
| 1 | City is gridded into 500 m × 500 m cells; time into 5-minute buckets. | Each row is one cell-bucket. Spatial correlation between neighbouring cells is ignored — a real simplification, and worth one sentence in your write-up. |
| 2 | Additive pricing: $\text{final} = \text{base} + \text{surge}$, with $\text{base} = 40 + 12\,d_{\text{km}} + 2\,t_{\text{min}}$. | You model the surge term only. The base is deterministic and is not a regression. |
| 3 | Gaussian likelihood: $y \sim \mathcal{N}(Xw, \sigma^2)$ with $\sigma = 10$ ₹. | Least squares is the MLE. σ is given, not estimated, so λ can be computed rather than only tuned. |
| 4 | Ridge prior $w \sim \mathcal{N}(0, \tau^2)$ with $\tau = 1$. | $\lambda = \sigma^2/\tau^2 = 100$. Compare this with the λ cross-validation picks — they will not agree, and explaining the disagreement is part of Task 2. |
| 5 | Lasso prior $w \sim \text{Laplace}(0, b)$ with $b = 5$. | $\lambda = 2\sigma^2/b = 40$ in the $\lVert y-Xw\rVert^2 + \lambda\lVert w\rVert_1$
parameterisation. Watch the scaling when you compare with sklearn — see the
note in Task 3. |
| 6 | Policy: surge capped at ₹150; surge set to 0 when $R/S < 1.5$. | The cap censors 21 of the 200 targets. Your coefficients on the drivers of extreme surge are biased toward zero as a result. |
| 7 | Split is time-based: trips 1–150 train, 151–200 test. | Do not shuffle. A random split would leak information across time and flatter every model equally. |
| 8 | Standardize features before any penalized fit. | Penalties are not scale-invariant. Fit on standardized columns; report coefficients in whichever units you state clearly. |
Tasks 1–3 must be implemented from scratch with NumPy. Call
scikit-learn only to verify, and show both numbers when you do. A submission that
calls Ridge() for Task 2 earns zero for that task regardless of the analysis around
it.
Task 1 · Maximum likelihood, by hand 10 marks · 30 min
Goal: derive the OLS estimator numerically, then watch it fail twice: once by becoming unstable, once by ceasing to exist.
1a · An ill-conditioned pair
Use is_rain and traffic_speed_kmph on the first six trips,
standardized using those six rows only.
- Compute $X^\top X$ (a $2\times2$ matrix) and $X^\top y$ by hand — show the arithmetic, not just the NumPy output.
- Report the sample correlation between the two columns and the determinant of $X^\top X$.
- Invert analytically using $\begin{pmatrix}a&b\\c&d\end{pmatrix}^{-1} = \frac{1}{ad-bc}\begin{pmatrix}d&-b\\-c&a\end{pmatrix}$ and obtain $\hat w_{\text{MLE}}$.
- Predict the surge for trip 2 (19:00, peak and rain, 6 drivers) and compare with the ₹150 actually charged.
- Now add trips one at a time. Refit on the first $n = 6, 7, \dots, 15$ trips and tabulate, for each $n$: the correlation, the determinant, both coefficients, and how far each coefficient moved from the previous row.
The two columns are correlated at about $-0.94$ on these rows. Between $n=6$ and $n=7$ one coefficient moves by roughly ₹11 per standard deviation, and keeps swinging for several more rows. One additional observation changes what the model says about rain by an amount comparable to the effect itself.
Marks are for the explanation, not the table. Connect the swing to the determinant and the $-r$ off-diagonal of the inverse. "The coefficients are unstable" is the symptom; "the determinant is 4.46, and the inverse's off-diagonal makes the two coefficients trade off almost one-for-one, so noise in either column is amplified into both" is a diagnosis.
1b · A pair where OLS does not exist
Now use is_rain and the derived
is_bad_weather = (is_rain == 1) & (traffic_speed_kmph < 25) on the
first ten trips.
- Print the two columns side by side. What do you notice?
- Compute $X^\top X$ and its determinant. Try to invert it and report exactly what happens.
- State, in one sentence, what "the maximum likelihood estimate does not exist" means here — not "NumPy raised an error" but what is true about the likelihood surface.
- Find the smallest $n$ at which the problem becomes solvable, and say what changed in the data at that row.
- Would Ridge return an answer on the first ten trips? Explain why, in terms of eigenvalues. (You do not need to compute it yet — Task 2 will.)
1c · The real thing
- Fit all eight base features on the full 150-trip training set. Report the coefficients, the condition number of $X^\top X$, and train and test RMSE.
- Compare that condition number with the ones from 1a. Is the full problem well conditioned? If so, say plainly that this dataset does not need regularization at this sample size — and keep that conclusion in mind for Task 2, where cross-validation will agree with you.
Check yourself: Walkthrough 1 runs these exact computations step by step, and Lab §5 plots the coefficient thrashing as $n$ grows. Use them to confirm your hand arithmetic, not to replace it.
Task 2 · Ridge as MAP 18 marks · 45 min
Goal: implement the Gaussian-prior MAP estimator and read a coefficient path. Walkthrough 2 derives the objective you are implementing, and Walkthrough 3 solves it.
- Implement $\hat w = (X^\top X + \alpha I)^{-1} X^\top y$ with
np.linalg.solve(notinv— say why in one line). - Fit for $\alpha \in \{0.1, 1, 10, 100, 1000\}$ on the eight base features. Tabulate all eight coefficients at each α.
- Plot the coefficient path: α on a log x-axis, coefficients on y, one line per feature. This is Deliverable 1.
- Identify the α at which
is_peakandis_raincome closest together, and explain the convergence using the equal-split argument. - Compute training and test RMSE at each α. Then run 5-fold cross-validation on the training split only over a log grid and report the CV-optimal α.
- Assumption 4 says $\lambda = \sigma^2/\tau^2 = 100$. Does CV agree? If not, which would you trust, and what does the disagreement tell you about the prior?
- Verify against
sklearn.linear_model.Ridge. Note that itsalphauses the same convention as your closed form; state the match to 3 decimals.
Cross-validation will choose an α far below 100, possibly near zero. That is not a bug: with 150 trips and 8 features the data is plentiful relative to the parameters, and the prior $\tau = 1$ is more confident than the evidence warrants. Say so rather than forcing the two to agree.
Task 3 · Lasso and coordinate descent 18 marks · 50 min
Goal: implement soft-thresholding, then use it on a real selection problem.
3a · The algorithm
- Implement
soft_threshold(rho, gamma)in three lines. - Implement cyclic coordinate descent for the objective $\frac{1}{2n}\lVert y - Xw\rVert^2 + \alpha\lVert w\rVert_1$, updating $w_j \leftarrow S(\rho_j, \alpha) / (\lVert x_j\rVert^2/n)$ and stopping when the largest coefficient change falls below $10^{-7}$.
- Verify against
sklearn.linear_model.Lasso(alpha=...)to 3 decimal places at three different α. If they disagree, your objective is scaled differently — find the factor rather than adjusting until it matches. - Plot the Lasso path over a log α grid and record the order of elimination.
3b · The new-city launch
Load new_city_features.csv: 60 trips, 120 candidate features. Six are real drivers,
and each real driver has a decoy planted beside it, correlated at $r \approx 0.9$–$0.96$.
Ground truth is in new_city_truth.csv — do not open it until step 3.
- Explain in one sentence why OLS cannot be computed here at all.
- Run your Lasso across $\alpha \in \{1, 2, 4, 6, 8, 10, 12, 15, 20, 25\}$. For each, record how many features survive.
- Now open the truth file. For each α report recall (how many of the six you found) and precision (what fraction of your selections are real). Plot both against α. Which α would you hand to the city-ops team, and why is it not the α with the best precision?
- The interesting part. Somewhere in that sweep, Lasso drops a real driver while keeping a feature that is not real. Identify which real driver goes first, which feature survives in its place, and the correlation between them. Then explain why this is the expected behaviour of an $\ell_1$ penalty rather than a failure of your code.
- Repeat with Elastic Net at $\rho = 0.5$ and at $\rho = 0.9$. Does recall improve? Does precision? Compare the number of features selected — and if Elastic Net turns out to be a worse tool for this particular job, say so and explain what the $\ell_2$ term is doing to sparsity.
- State the theoretical bound on how many features Lasso can select when $n = 60$, and say whether you ever came near it.
3c · The same penalty, a different question
You meet the ℓ₁ penalty again in Task 6, on a classification target. Set the comparison up now, in one cell, and keep the output:
- Record the set of features your Lasso keeps at $\alpha = 2$ on the nine-feature regression.
- Write down, before fitting anything, which features you expect an
ℓ₁-penalized logistic model to keep once the target becomes
high_surge = surge > ₹100. Task 6c checks your prediction.
Step 5 has a counter-intuitive answer here, and reporting it honestly is worth more than reporting the answer you expected. The grouping effect is what you want when a correlated group is the finding (Task 4), and not what you want when the correlated partner is a decoy. Knowing which situation you are in is the skill being assessed.
Check yourself: Lab §6 runs this live.
Task 4 · Elastic Net and the grouping effect 18 marks · 60 min
Goal: show that the three estimators handle a correlated group in three distinguishable ways.
- Construct the derived feature
is_bad_weather = (is_rain == 1) & (traffic_speed_kmph < 25). Report its correlation with each of its two parents. - Fit all three estimators on the nine features (eight base plus the new one), each tuned by
5-fold CV. Report the coefficients on
is_rain,traffic_speedandis_bad_weatherin a single table. - Verify the three predicted behaviours:
- Ridge keeps all three with comparable magnitudes;
- Lasso concentrates on roughly one and shrinks the others hard;
- Elastic Net keeps the group together while still zeroing
is_weekend.
- Sweep $\rho \in \{0.1, 0.3, 0.5, 0.7, 0.9, 1.0\}$ at fixed α and plot the three group coefficients against ρ. At what ρ does the group start to break apart?
- Test the stability claim directly: bootstrap the training set 200 times, refit Lasso and Elastic Net each time, and report how often each of the three weather features is selected. This is the empirical version of the grouping bound.
Step 5 is the one that matters. "Lasso picks one at random" is a claim about variability across resamples, and the bootstrap measures it. A selection-frequency table proves the point rather than asserting it.
Task 5 · The surge engine 18 marks · 30 min
Goal: assemble a system rather than a model.
- Wrap your best estimator in a function
price(hour, is_rain, traffic, drivers, requests, distance_km, ...) → dictreturning the raw model output, the surge after policy, the base fare, and the final fare. - Implement the policy layer outside the model:
ratio = requests / drivers if ratio < 1.5: surge = 0 surge = min(max(surge, 0), 150) final = base + surge - Simulate: 19:00, BKC, raining, 5 drivers, 25 open requests, 8 km trip. Report every intermediate quantity. Should a driver 3 km away in Andheri reposition? Use the rule "yes if surge > ₹50" and state what that threshold is implicitly assuming about the driver's cost.
- Sweep the drivers-available count from 1 to 40 with everything else fixed, and plot the resulting surge. Mark where the cap binds and where the threshold switches surge off. Comment on the discontinuity at $R/S = 1.5$ — is a step function the right policy, and what would a rider experience just either side of it?
- Compute the price elasticity your model implies: if surge rises by ₹50, by how much would demand have to fall for $R/S$ to return to 1? Explain why your data cannot answer this and what experiment would.
Check yourself: Case study §7 is a working reference implementation of steps 1–3.
Task 6 · Logistic regression 18 marks · 60 min
Goal: change the likelihood, keep the priors, and find that the penalties behave exactly as before — then ask whether the binary target was worth creating.
6a · Why not least squares
Build the label high_surge = (surge_additive_inr > 100) on the nine features.
- Report the number of positives in train and test, and the base rate — the accuracy of always predicting "no alert". Every accuracy you quote from here on must be shown next to it.
- Fit ordinary least squares to the 0/1 label. Count how many of the 150 fitted values fall outside $[0,1]$, and say in one sentence why that disqualifies it as a probability model.
- Write down the Bernoulli log-likelihood and show that maximising it is minimising the average log-loss. Two lines; it is the same manoeuvre as Task 1 with a different density.
6b · Implement it
- Implement penalized logistic regression from scratch, minimising $\frac{1}{n}\sum_i\big[-y_i\log p_i-(1-y_i)\log(1-p_i)\big] + \alpha\rho\lVert w\rVert_1 + \frac{\alpha(1-\rho)}{2}\lVert w\rVert_2^2$ with $p_i = \sigma(x_i^\top w + b)$ and the intercept unpenalized. Either iteratively reweighted least squares (for $\rho = 0$) or proximal gradient descent (any $\rho$) is acceptable; state which you chose and why.
- Verify against
sklearn.linear_model.LogisticRegressionat $C = 1/(n\alpha)$, to 3 decimal places.
If you compare against solver='liblinear', your coefficients will disagree by far
more than solver tolerance and no amount of tuning will fix it: liblinear penalizes the
intercept and your objective does not. Use lbfgs for ℓ₂ or
saga for ℓ₁ and elastic net. Diagnosing this yourself and saying so earns credit —
it is the same discipline as the $1/2n$ factor in Task 3a.
6c · The penalties, again
- Plot coefficient paths over a log α grid at $\rho = 0$ and $\rho = 1$. Confirm that ℓ₂ never reaches zero and ℓ₁ does.
- Record the ℓ₁ elimination order and compare it with your Task 3c prediction. It will probably be wrong. Explain why — which features go first here, and what does that tell you about what an ℓ₁ ordering actually measures?
- Tune all four models (no penalty, ℓ₂, ℓ₁, elastic net) by 5-fold cross-validation on log-loss, not accuracy. Report held-out log-loss, AUC, accuracy and non-zero count for each.
6d · The threshold is not the model's job
- Plot the ROC curve for your best model and report AUC.
- Give the confusion matrix at thresholds 0.3, 0.5 and 0.7, stating how many real alerts are missed and how many false alarms raised at each.
- Dispatch tells you a missed alert costs roughly four times a false alarm. Choose the threshold that minimises expected cost, show the arithmetic, and say which layer of the system that number belongs in.
6e · Was the label worth making?
The binary target was manufactured by cutting a continuous one. Measure what that cost.
- Take your Ridge model from Task 2, predict the surge in rupees on the held-out trips, and threshold the prediction at ₹100 to get a yes/no.
- Compare its accuracy, and the AUC implied by ranking its rupee predictions, against your best purpose-built classifier.
- Conclude. If thresholding the regression matches or beats the classifier, say so plainly and explain what dichotomising cost you. If it does not, explain what the classifier is exploiting that the regression is not.
6e is a question about modelling judgement, not implementation. The strongest answers notice that the regression retains information the classifier discarded — how far above the cut a cell sits — and that this is the same objection raised against the hard $R/S > 1.5$ threshold in the case study, arrived at from the other direction.
Check yourself: the logistic regression lab runs every part of this interactively, and Theory §8 has the derivation.
Bonus · The full posterior +10 marks
- Compute the Gaussian posterior $\Sigma = (X^\top X/\sigma^2 + I/\tau^2)^{-1}$, $\mu = \Sigma X^\top y/\sigma^2$ with $\sigma = 10$, $\tau = 1$.
- Confirm numerically that $\mu$ equals your Ridge solution at $\lambda = 100$. Explain why in one sentence.
- Report each coefficient as $\hat w_j \pm 1.96\sqrt{\Sigma_{jj}}$. Which intervals contain zero? What does that tell you, and how does it compare with what Lasso decided about the same features?
- For the BKC scenario, compute the posterior predictive variance $x_\star^\top \Sigma x_\star + \sigma^2$ and quote the surge as "₹X ± ₹Y".
- Which of the two terms in that variance dominates? What would you have to do to reduce each of them?
- Write two sentences a product manager could put in front of a rider. Then write the one sentence you would refuse to let them write, and say why.
What to hand in
Coefficient path figure
One page, three panels: Ridge, Lasso and Elastic Net paths on shared axes, with the CV-optimal α labelled on each. A reader should be able to tell which estimator zeroes coefficients without reading the text.
Comparison table
Train RMSE, test RMSE, test R², non-zero count and chosen α for all four estimators. State whether the differences exceed resampling noise.
Deployment recommendation
300 words. Which estimator ships for Mumbai and why. Name the deciding constraint (interpretability, stability across refits, latency or accuracy) and be honest if accuracy is not it.
ROC curve and a justified threshold
One figure with the ROC curve and AUC, the confusion matrix at your chosen threshold, and the cost arithmetic behind it. Show the base rate beside every accuracy you report.
Marking rubric
| Band | Looks like |
|---|---|
| Distinction (70+) | Correct implementations, with a write-up that explains mechanisms rather than restating outputs. Reports at least one result that contradicted expectation and investigates it — Task 6c and 6e are both built to produce one. Notices the censoring at ₹150, or the non-linear $50/(S+1)$ term, unprompted. Distinguishes "these models differ" from "these models differ by more than noise". |
| Merit (60–69) | All five tasks complete and correct. Figures are labelled and readable. Cross-validation is done on the training split only. Conclusions follow from the evidence presented. |
| Pass (50–59) | Estimators implemented and broadly correct; some analysis is thin or descriptive. May confuse training and test error in places, or quote α to spurious precision. |
| Fail | Library calls substituted for the required from-scratch implementations; test set used to select hyperparameters; conclusions unsupported by the numbers shown. |
1. Cross-validating on all 200 trips and then reporting test RMSE from the
same 200: the test set is now part of model selection and the number means nothing.
2. Forgetting to standardize before a penalized fit, so traffic_speed
(range ≈ 55) is penalized far more than is_rain (range 1).
3. Reporting that Lasso "selected the important features" without checking
selection stability (Task 4, step 5).