Data Science Logistic Regression β A 42 school project to classify Hogwarts students into their house using logistic regression and exploratory data analysis.
Note
This project combines data exploration, visualization, and machine learning to predict student houses from course grades using custom-built logistic regression with multiple gradient descent variants.
- Overview
- Feature Highlights
- Architecture
- Getting Started
- Scripts & Usage
- Project Structure
- Further Reading
DSLR is a end-to-end machine learning project that classifies students into Hogwarts houses (Gryffindor, Slytherin, Ravenclaw, Hufflepuff) using their course grades. The pipeline includes:
- Data Exploration β Compute and display descriptive statistics (mean, std, percentiles, outliers).
- Visualization β Generate scatter plots, histograms, and pair plots to explore feature distributions and correlations.
- Feature Normalization β Standardize features and handle missing values for model training.
- Model Training β Implement logistic regression with three gradient descent strategies: batch, stochastic, and mini-batch.
- Predictions β Load trained weights and classify new students into their houses.
The entire system uses hand-written statistical functions (no NumPy-based shortcuts for stats) and a custom logistic regression implementation to reinforce ML fundamentals.
- Custom Statistics β Implement mean, standard deviation, percentiles, median, mode, and outlier detection without relying on built-in statistical libraries.
- Multiple Gradient Descent Methods β Batch GD, stochastic GD, and mini-batch GD with early stopping via rolling-window loss tracking.
- Flexible Training β Train with
--gd-type batch|stochastic|mini-batchto compare convergence and accuracy. - Comprehensive Visualization β Scatter plots, histograms, and pair plots to identify feature importance and inter-house patterns.
- One-vs-Rest Classification β Train independent binary logistic regression models for each house and use argmax for multi-class predictions.
- Normalized Pipeline β Handle missing values (fill with median), normalize features, and persist normalization stats for test-time consistency.
- Bonus Statistics β Optional
--bonusflag indescribe.pyshows NaN counts, ranges, modes, and outlier counts per feature.
dslr/
βββ describe.py # Print descriptive statistics for the dataset
βββ histogram.py # Plot histograms of scores by house
βββ scatter_plot.py # Plot two features colored by house
βββ pair_plot.py # Grid of scatter plots and histograms (pair-wise)
βββ logreg_train.py # Train logistic regression models
βββ logreg_predict.py # Load weights and predict houses for new data
βββ utils.py # Shared utilities (stats, data loading, normalization)
βββ datasets/
β βββ dataset_train.csv # Training data (with Hogwarts House column)
β βββ dataset_test.csv # Test data (no house labels)
βββ requirements.txt # Python dependencies
βββ LICENSE
βββ README.md # This file
- Python 3.8+
- pip (or your preferred package manager)
pip install -r requirements.txtThe project uses:
pandasβ data manipulationnumpyβ numerical computingmatplotlibβ visualizationscikit-learnβ accuracy scoring during trainingtabulateβ pretty-printed statistics tables
Both training and test datasets must be CSV files with:
- A
Hogwarts Housecolumn (training only) - 13 course features:
- Arithmancy, Astronomy, Herbology, Defense Against the Dark Arts
- Divination, Muggle Studies, Ancient Runes, History of Magic
- Transfiguration, Potions, Care of Magical Creatures, Charms, Flying
Missing values are represented as nan. The trainer fills them with the median; the predictor mirrors this approach.
# Basic statistics
python describe.py datasets/dataset_train.csv
# Include bonus stats (NaN count, range, mode, outliers)
python describe.py datasets/dataset_train.csv --bonus# Single scatter plot (default: Defense Against the Dark Arts vs Astronomy)
python scatter_plot.py datasets/dataset_train.csv
# Scatter plot for two specific features
python scatter_plot.py datasets/dataset_train.csv --subject1 "Potions" --subject2 "Charms"
# Histograms for a single course
python histogram.py datasets/dataset_train.csv --course "Potions"
# Histograms for all 13 courses (4Γ4 grid with legend)
python histogram.py datasets/dataset_train.csv
# Pair-wise grid: scatter plots (lower triangle) and histograms (diagonal)
python pair_plot.py datasets/dataset_train.csvTraining produces a weights.json file with learned weights and normalization stats.
# Batch gradient descent (full batch per epoch)
python logreg_train.py datasets/dataset_train.csv
# Stochastic gradient descent (one sample per update)
python logreg_train.py datasets/dataset_train.csv --gd-type stochastic
# Mini-batch gradient descent (32 samples per batch by default)
python logreg_train.py datasets/dataset_train.csv --gd-type mini-batchOutput:
- Training progress logged every 100 epochs
- Final accuracy on training data
weights.jsonsaved to the current directory
Load the trained model and predict houses for a test set:
python logreg_predict.py datasets/dataset_test.csvOutput:
houses.csvwith columns:Index, Hogwarts House
Compute and display basic statistics (count, mean, std, min, 25%, 50%, 75%, max) for all 13 features.
python describe.py <data_path> [--bonus]<data_path>β path to the CSV file--bonusβ also show NaN count, range, mode, and number of outliers per feature
Output: Pretty table with statistics per feature.
Plot two features (x vs y) with points colored by house.
python scatter_plot.py <data_path> [--subject1 <first>] [--subject2 <second>]<data_path>β path to the CSV file--subject1β feature for x-axis (default: "Defense Against the Dark Arts")--subject2β feature for y-axis (default: "Astronomy")
Plot feature distributions (one or all courses) as histograms with house-specific colors.
python histogram.py <data_path> [--course <feature>]<data_path>β path to the CSV file--courseβ single course name; omit to plot all 13 features in a 4Γ4 grid
Generate a 13Γ13 grid of plots:
- Diagonal: histograms (one feature)
- Lower triangle: scatter plots (two features)
- Upper triangle: hidden to avoid redundancy
python pair_plot.py <data_path><data_path>β path to the CSV file
Train one-vs-rest logistic regression models (one per house) and save weights and normalization stats.
python logreg_train.py <train_data> [--gd-type {batch,stochastic,mini-batch}]<train_data>β path to the training CSV--gd-typeβ gradient descent method (default: "batch")batchβ full-batch GDstochasticβ online GD (one sample per update)mini-batchβ mini-batch GD (32 samples per batch)
Output:
- Per-house training progress and final accuracy
weights.jsoncontaining:featuresβ list of 8 training features (14 total minus 5 excluded)meansandstdsβ normalization parameters per featureweightsβ learned coefficients (including bias) per house model
Load trained weights and predict houses for a test set.
python logreg_predict.py <test_data><test_data>β path to the test CSV (no "Hogwarts House" column needed)
Output:
houses.csvwith columnsIndex, Hogwarts House
The script:
- Loads the test data
- Loads
weights.json(normalization stats and model weights) - Normalizes test features using stored means and stds
- Computes sigmoid probabilities for each house
- Selects the house with the highest probability per student
- Writes predictions to
houses.csv
dslr/
βββ describe.py # Descriptive statistics (mean, std, percentiles, etc.)
βββ histogram.py # Histogram visualization by house
βββ scatter_plot.py # Scatter plot (two features, colored by house)
βββ pair_plot.py # Pair-wise grid (histograms + scatter plots)
βββ logreg_train.py # Train logistic regression models
βββ logreg_predict.py # Predict houses using trained weights
βββ utils.py # Shared utilities
β βββ HOUSES # Tuple of house names
β βββ FEATURES # All 13 course features
β βββ TRAIN_FEATURES # Subset of 8 features used for training
β βββ load_data() # Load and validate CSV
β βββ score_by_house() # Group students by house
β βββ load_weights() # Load JSON weights file
β βββ sigmoid() # Sigmoid activation
β βββ ft_*() # Custom statistics (mean, std, median, etc.)
β βββ normalize() # Standardize features
β βββ normalize_features() # Full normalization pipeline
βββ datasets/
β βββ dataset_train.csv # Training data
β βββ dataset_test.csv # Test data
βββ requirements.txt # Python dependencies
βββ LICENSE
βββ README.md # This file
- Logistic Regression β The core model uses a one-vs-rest approach: each house gets its own binary classifier that predicts "this house" vs "not this house." At test time, we pick the house with the highest probability.
- Gradient Descent β Three variants are implemented:
- Batch updates on the full dataset per epoch (most stable but slow).
- Stochastic updates on each sample (noisy but fast, may require more epochs).
- Mini-batch uses a fixed batch size (good balance).
- Early Stopping β Training terminates when the rolling average loss (last 100 epochs) stops improving by a threshold (patience=10, min_delta=1e-4).
- Feature Engineering β The 5 excluded features (
Arithmancy,Care of Magical Creatures,Transfiguration,History of Magic,Muggle Studies) were deemed less useful for classification during the design phase. - Data Normalization β Missing values are filled with the median (computed on training data); features are standardized with z-score normalization (z = (x - mean) / std).
This project was developed in collaboration with Cedric.
For questions or improvements, feel free to open an issue or contribute. Happy classifying! π§ββοΈ