Thanks for taking the time to contribute. This is a notebook-driven NLP / ML project — the guidelines below keep it reproducible, reviewable, and runnable on modest hardware.
- Ways to contribute
- Ground rules
- Development setup
- Working on the notebooks
- Reproducibility & the artifact contract
- Testing your changes
- Coding style
- Commit & pull-request conventions
- What NOT to commit
- Good first issues
- Reporting bugs
- Code of Conduct
- Bug reports and fixes — pipeline breakage, wrong metrics, data-loading edge cases, memory blow-ups.
- Features from the roadmap — calibrated probabilities, sub-routers
for the non-
Loanslanes, a DistilBERT baseline, packagingroute_complaint()as a CLI, CI. - Documentation — clearer explanations, diagrams, worked examples.
- Performance / memory improvements — the notebooks are deliberately written to run on a laptop; keep it that way.
- The notebooks are the source of truth. There is no separate library — each
NN_name.ipynbis self-contained and reads the artifacts written by the notebooks before it (00→05). - A clean "Restart & Run All" must pass, top to bottom, on the
complaint-router-venvkernel. - One concern per pull request. A metrics change and a feature change are two PRs.
- Be honest about results. If a change lowers a score, say so and explain the trade-off. Numbers in the README must match a real run.
Full instructions are in the README Quickstart. In short:
python -m venv .venv
.venv\Scripts\activate # Windows • source .venv/bin/activate elsewhere
pip install -r requirements.txt
python -m nltk.downloader punkt punkt_tab stopwords wordnet omw-1.4 \
averaged_perceptron_tagger averaged_perceptron_tagger_eng vader_lexicon
python -m ipykernel install --user --name complaint-router-venv \
--display-name complaint-router-venv00_fetch_data pulls the raw data once; every later run reuses data/raw/ because the
default is FORCE_REFETCH = False. 01's lemmatization is cached
(data/processed/lemma_cache.parquet), so re-running it after a config change is seconds.
- Edit cells directly. Match the surrounding style — short comments,
snake_case, scikit-learn idioms. - Keep configuration in the clearly-marked config cell near the top of each notebook
(
MAX_PER_LANE,MERGE_*switches,USE_CHAR_NGRAMS, theCgrid,N_TOPICS, …). Don't scatter magic numbers through the code. - Every non-trivial code cell should be preceded by a markdown header that says what it does.
- If you add a slow step, cache it — follow the
lemma_cache.parquetpattern in01(key bycomplaint_id, only compute the misses, persist). - Prefer adding a toggle (
USE_X = False) over hard-swapping behaviour, so reviewers can A/B it.
- Preserve
RANDOM_SEED = 42and the stratified 70 / 15 / 15 split. - Never tune on the test split. Choose hyper-parameters on validation only; report test once, at the end.
- If you change what a notebook writes to
data/processed/ormodels/, you must also update:- every downstream notebook that reads it, and
- the Intermediate artifacts and Configuration knobs tables in the README.
- Metrics: report per-class and macro / weighted roll-ups. For a router, per-lane recall is the headline — a model that silently drops a lane can still post high accuracy.
Run the notebook you touched and everything downstream:
jupyter nbconvert --to notebook --execute --inplace \
--ExecutePreprocessor.timeout=3600 \
--ExecutePreprocessor.kernel_name=complaint-router-venv \
notebooks/05_classification.ipynb- A change to
01needs01→05. A change to05needs only05. - On a memory-constrained machine, run notebooks one at a time (see README Troubleshooting) — a six-notebook loop can be killed mid-run.
- Confirm the notebook has no error outputs and the committed cell outputs match the committed code.
- Python: PEP 8, ~100-column lines, f-strings, type hints on non-trivial helpers.
- Vectorized pandas / numpy over Python loops.
- Every plot gets a title, axis labels, and a legend where relevant, and must be legible in a rendered notebook.
- Imperative, present-tense subjects:
add char n-gram union to 02,fix stale row-count label in 05,cache lemmatization in 01. - One logical change per commit where practical.
- PR description: what changed, why, and the before / after numbers if a metric moved — paste the relevant cell output.
- Re-run the affected notebooks so committed outputs match committed code. Plots are fine to keep; strip multi-MB embedded data blobs.
data/(raw, processed, caches) andmodels/*.joblib— all regenerable, all git-ignored..venv/,__pycache__/,*.log, editor/IDE files.- Notebook outputs containing large embedded binary data.
- Any real personal data — the CFPB narratives are already redacted (
XXXX); keep it that way and never add un-redacted text.
From the README Roadmap:
- Wrap the prod estimator in
CalibratedClassifierCVsoconfidenceis a realp(lane). - Add sub-routers for the
Reporting & CollectionsandBanking & Paymentslanes. - Package
route_complaint()as an importable module +python -m complaint_router "<text>". - A tiny fixture sample + a GitHub Actions
nbconvert --executesmoke test. pyLDAvisinteractive topic view in04.
Open an issue with:
- what you ran (notebook + cell),
- the full traceback,
- OS / Python version /
pip freeze(or at least scikit-learn, pandas, numpy versions), - free-RAM figure if it looks like an out-of-memory kill.
Be respectful and assume good faith. Keep discussion technical and constructive. Harassment or discrimination of any kind is not tolerated; maintainers may remove comments, commits, or contributors that violate this.