A self-extending practice repo for a data science / applied ML internship's online coding test: Data Cleaning & Preprocessing, Data Querying & Retrieval, Exploratory Data Analysis & Visualization, and Machine Learning & Predictive Modeling.
Start with CURRICULUM.md — the detailed checklist of exactly which
operations to be fluent in, grounded in public reports of the real assessment format
(90–120 min, Python + pandas/numpy/scikit-learn, plus a dedicated SQL section).
CURRICULUM.md topic-by-topic checklist — read this first
quiz/
quiz.html self-contained MCQ practice page — open directly in a browser
questions.yaml source data for quiz.html — extend this, then rebuild
README.md how the quiz works, how to add questions
tasks/
INDEX.md auto-generated status table (run tools/build_index.py to refresh)
001_.../ one folder per task
meta.yaml topic, difficulty, status
task.md the brief: business framing, dataset, numbered deliverables
work.ipynb <- you work here
data/
generate_data.py regenerates the dataset (synthetic, seeded, reproducible)
*.csv
solution_revealed.ipynb <- appears only after you run reveal_solution.py
solutions/
001_.../solution.ipynb the hidden worked solution — don't open this until you've tried
tools/
new_task.py scaffold a new task folder
reveal_solution.py copy a solution into its task folder once you're ready
run_notebook.py execute a notebook headlessly (for a quick compare)
check_task.py self-grade a submission against a task's expected output (autograded tasks only)
build_index.py regenerate tasks/INDEX.md from all the meta.yaml files
build_quiz.py regenerate quiz/quiz.html from quiz/questions.yaml
task_prompt_template.md the prompt to hand an LLM to write a new task's content
nbutil.py tiny helper for building .ipynb files programmatically
The real test has a ~9-15 question multiple-choice section (probability, ML fundamentals, model evaluation) separate from the coding problems. Practice that with:
open quiz/quiz.html # or xdg-open on Linux — no server needed, fully offlineAnswering any option reveals the correct answer and explanation immediately. See
quiz/README.md for how to add more questions (also LLM-extendable, same
pattern as tasks).
business_framed(tasks 001-004) — a sentence of context, an open-ended deliverable list, graded by your own judgment against the hidden solution.exact_io_contract(task 005) — terse, no framing, fixed input/output filenames, lettered sub-steps, strict dtype requirements, and a real autograder. This is the closer match to how the actual platform's questions are phrased (see task 005's brief and notes for a worked example of the classic "NaN forces float64" dtype trap) — prefer this style when generating new tasks unless you specifically want to practice the more open-ended judgment calls.
For exact_io_contract tasks, self-check your output with:
python tools/check_task.py 005It reports each check (columns, row count, dtypes, values) pass/fail independently, mirroring
the platform's per-step partial scoring. Some tasks bundle several small lettered parts into one
task instead of many tiny folders (e.g. tasks/008_.../, seven parts a–g) — for those,
python tools/check_task.py 008 grades every part in one run, or --part e for just one.
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
jupyter lab- Open
tasks/00X_.../task.md, read the brief. - If
data/*.csvisn't there yet, runpython data/generate_data.pyfrom inside that task folder (or from anywhere, adjusting the path). - Work the problem in
tasks/00X_.../work.ipynb, in Jupyter Lab. - When you want to check yourself:
This copies the hidden solution into
python tools/reveal_solution.py 00X
tasks/00X_.../solution_revealed.ipynb, right next to your own notebook. Open both as tabs in Jupyter Lab and compare — or run both headlessly and diff outputs:python tools/run_notebook.py tasks/00X_.../work.ipynb python tools/run_notebook.py tasks/00X_.../solution_revealed.ipynb
- Update
status:in that task'smeta.yaml(in_progress→done), then:to refreshpython tools/build_index.py
tasks/INDEX.md.
The solution is never shown until you explicitly reveal it — solutions/ sits outside tasks/
specifically so it doesn't tempt you while browsing the file tree.
This is meant to grow indefinitely. To add a new task:
python tools/new_task.py --title "Window functions on sales data" \
--topic data_querying --difficulty mediumThis scaffolds an empty tasks/00N_.../ + solutions/00N_.../ pair (folders, meta.yaml,
starter task.md, empty work.ipynb/solution.ipynb). It does not write the actual
content — hand that off to an LLM (this repo was built with, and is meant to be extended with,
Claude Code) using the prompt in tools/task_prompt_template.md,
which points it at CURRICULUM.md for topic coverage and an existing task as a style reference.
A reasonable cadence: pick one under-covered subtopic from CURRICULUM.md (cross-check against
tasks/INDEX.md's "By topic" counts), generate a task for it, solve it yourself, reveal and
compare, repeat.
- Data is synthetic and seeded, generated by a small numpy/pandas script per task — no external downloads, fully reproducible, and the generator deliberately bakes in the specific data-quality issues or signal the task is testing (not left to chance).
- SQL tasks run against real SQL via DuckDB, directly on the CSVs/ dataframes — no database server to stand up, but genuine SQL syntax, not a pandas approximation of it.
- Solutions favor speed and correctness over polish, deliberately mirroring what the real test rewards (per public candidate reports: ~60–70% correctness was reportedly enough to pass) — don't over-index on making your own code beautiful under time pressure.
- Every solution step traces back to an explicit deliverable. If
solution.ipynbdoes something (e.g. outlier correction, not just the "obvious" cleaning), that step is always its own numbered/lettered item intask.md— never an undocumented surprise. If you ever spot a solution doing something itstask.mddoesn't ask for, that's a bug — flag it.