Everything runs on NumPy, pandas, Matplotlib and scikit-learn. In Colab, upload
uber_surge_mumbai.csv and new_city_features.csv alongside the notebook;
locally, keep them in a data/ folder next to it. If a CSV is missing the notebook
regenerates it from the same seed.
Starter notebooks
01 · Least squares and Ridge
Hand computation of $X^\top X$ on five trips, the determinant, the explicit $2\times2$ inverse; then Ridge in closed form, the coefficient path, and 5-fold CV. Includes the instability table you must fill in.
≈ 30 cells · NumPy only for the estimators
02 · Lasso by coordinate descent
Soft-thresholding from scratch, cyclic coordinate descent, verification against
sklearn.Lasso to three decimals, the elimination-order path, and the
120-feature / 60-trip new-city selection problem.
≈ 34 cells · includes the $p \gg n$ dataset
03 · Elastic Net and the grouping effect
The derived is_bad_weather feature, the three-way comparison on
the correlated group, the ρ sweep, and the bootstrap selection-stability
experiment that turns "Lasso picks one at random" into a measurement.
≈ 28 cells · 200 bootstrap refits, runs in seconds
04 · The surge engine and the posterior
The price() function with its policy layer, the BKC simulation,
the supply sweep with the cap and threshold marked, and then the full Gaussian posterior with
credible intervals and predictive variance.
≈ 30 cells · ends with a deployable function
05 · Logistic regression
A Bernoulli likelihood in place of a Gaussian one, with the same priors.
Penalized logistic regression by proximal gradient descent, verified against
sklearn; coefficient paths; ROC and a threshold chosen from a stated cost ratio;
and a measurement of what dichotomising the target cost.
≈ 20 cells · includes the liblinear intercept trap
Everything at once
One archive with all ten notebooks, both datasets, the ground-truth file and the generator script.
Conventions used in the code
| Convention | Why |
|---|---|
| Objective is $\frac{1}{2n}\lVert y-Xw\rVert^2 + \alpha\rho\lVert w\rVert_1 + \frac{\alpha(1-\rho)}{2}\lVert w\rVert_2^2$ | Identical to scikit-learn's ElasticNet, so your solver and the library
agree to machine precision. The $1/2n$ matters. |
| Ridge closed form uses $\alpha_{\text{sklearn}} = n\alpha$ | sklearn.Ridge omits the $1/n$. This factor is the most common reason a
path plot looks shifted. |
| Standardize on the training split only, then apply to test | Computing the mean and sd over all 200 trips leaks test information into training. A small effect here, a bad habit elsewhere. |
| Time-based split, never shuffled | Rows are in time order. A random split lets the model see the future. |
np.linalg.solve(A, b) rather than inv(A) @ b |
Faster and numerically better conditioned. The explicit inverse appears exactly once, in Task 1, because there you are asked to look at it. |
| Logistic objective is mean log-loss plus the same penalty, intercept unpenalized | Matches LogisticRegression at $C = 1/(n\alpha)$ — but only with
lbfgs or saga. liblinear penalizes the intercept,
which this objective does not. |
| Random seed fixed at 42 everywhere | Bootstrap numbers should match the solution notebook exactly; if not, something else differs. |
They are published deliberately: checking an answer against a correct one is how people learn to debug numerical code. But a coordinate descent loop you have read is not one you can write. Attempt each cell first, and if you consult the solution, say so in your submission.
The same computations, without leaving the browser, are in the algorithm walkthroughs and the lab.