Thirteen runnable scripts, simplest first. Each one is written the way a user of
the installed package writes code — everything comes from the top-level
oop_ml import, and no example reaches into the library's internal module
paths. Reading one tells you what your own code should look like.
Each carries its reasoning in the module docstring: the reported numbers are the point, and the prose says what to notice in them.
git clone https://github.com/aemonalgiz-dev/oop_ml.git
cd oop_ml
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"Then, from the repository root:
python -m examples.simple_regressionThe scripts import oop_ml as an installed package, so once the editable
install is in place they behave exactly as your own project would. What they
additionally import from examples.datasets and examples.reporting are the
two local helpers described below, which is why they run from the repository
root rather than from anywhere.
| # | Script | What it shows |
|---|---|---|
| 1 | simple_regression |
The three-call shape: construct, fit, ask. Why evaluate returns an object rather than a number. |
| 2 | multiple_regression |
Features carry names, so coefficients are addressed by name and predict cannot be fooled by column order. |
| 3 | gradient_descent |
The same objective as the closed form, walked to instead of jumped to — and the two hyperparameters that arrive with it. |
| 4 | regularization |
Ridge shrinks, lasso selects. Why that difference falls out of the shape of the penalty. |
| 5 | polynomial_curves |
Fitting a curve without changing the model at all, and what rising degree costs on held-out data. |
| 6 | standardization |
Why a penalty and a learning rate care about units when least squares does not — and where leakage gets in. |
| 7 | model_selection |
The capstone: hold out, cross-validate, choose, refit, report once. |
| 8 | logistic_regression |
The same API pointed at a label instead of a quantity, how to read a coefficient that multiplies the odds, and two solvers arriving at one maximum 749 epochs apart. |
| 9 | classification_metrics |
Why accuracy is the wrong number on a rare class, and what moving the threshold buys and costs. |
| 10 | multiclass_classification |
Softmax against one-vs-rest on three classes, and why macro and micro averaging are two different claims about one model. |
| 11 | tokenization |
Four vocabularies from one corpus: how byte pair encoding, WordPiece, the unigram model and a byte tokenizer each spell a word they have seen, one they have not, and one spelled in letters the corpus never used; and what merge dropout does to a spelling while a model is training. |
| 12 | embeddings |
Four tables from one two-topic corpus: word2vec, GloVe, latent semantic analysis and pointwise mutual information each put the cooking words together and the sailing words together, and the function words between; what word2vec recorded while it learned; and a text as the mean of its words. |
datasets.py— synthetic data, each generator returning aSyntheticRegressionor aSyntheticClassificationthat pairs the data with the coefficients that produced it. The truth is carried asCoefficients, the same type the models learn, so every example can report the estimate beside the answer. The classification generators draw labels from the true probability rather than thresholding it, so the classes overlap the way real ones do.reporting.py— theReportobject every script writes through, plus the logging setup.
| Level | Carries |
|---|---|
INFO |
The report itself — headings, tables, and the prose saying what to notice. The default. |
WARNING |
The modelling telling you something: a fit that did not converge, a held-out R² gone negative, a deliberately leaky pipeline. |
ERROR |
An exception raised and caught on purpose, to show a guard firing. |
DEBUG |
Mechanical detail — shapes, seeds, per-fold scores. Off by default. |
Warnings and errors are prefixed ([warning] …) so they break out of the report
text; INFO lines are emitted exactly as written, which is what keeps the
tables aligned.
Add --verbose for the DEBUG detail:
python -m examples.model_selection --verboseThat turns the cross-validation summary into per-fold scores, which is where you can see the disagreement the spread column is summarising.
Configuration happens only in each script's __main__ block, never on import —
so test/test_examples.py can call every main() without seven modules
fighting over the root logger.
Every dataset here is generated, and that is deliberate. With real data the true coefficients are unknown, so a fitted model can only be compared against other fitted models and each example becomes a plausibility argument. Generating the data means the answer is available to report in the next column.
The trade-off is honest to state: synthetic data is well behaved. There are no missing values, no measurement error in the predictors, no drift between training and deployment. The examples show the mathematics working, not the data cleaning that dominates real work.
Every seed is fixed, so these scripts print the same values on every run and across machines. Two of the tables are worth pausing on:
polynomial_curves— train R² rises monotonically to 0.98 while test R² falls to −133. A model that fits its training data almost perfectly and is worse than useless on new data, in six lines of output.model_selection— held-out R² of 0.70 with a penalty against 0.61 without one, on data chosen so that a penalty genuinely helps. Alongside an in-sample score of 0.91, which is what the same model claims about itself.
The examples are covered by test/test_examples.py, which runs each one and
fails if it raises — so they cannot quietly rot as the library changes.